Compare commits

..

No commits in common. 'main' and '2.7.x' have entirely different histories.
main ... 2.7.x

@ -1,7 +1,5 @@
# .git-blame-ignore-revs
# Reformat code following spring-javaformat upgrade
df5898a1464112f185d295d585740de696934a12
c4de86c244acdcff69ed0aecacd254399be79ce2
b07269a018a4a9d4c029aba7dd8a15fa66df681c

@ -10,10 +10,10 @@ jobs:
runs-on: ubuntu22-8-32
if: ${{ github.repository == 'spring-projects/spring-boot' }}
steps:
- name: Set up JDK 17
- name: Set up JDK 8
uses: actions/setup-java@v3
with:
java-version: '17'
java-version: '8'
distribution: 'liberica'
- name: Check out code

@ -2,16 +2,6 @@
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="LombokGetterMayBeUsed" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullableProblems" enabled="false" level="WARNING" enabled_by_default="false">
<option name="REPORT_NULLABLE_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_METHOD_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOTNULL_PARAMETER_OVERRIDES_NULLABLE" value="true" />
<option name="REPORT_NOT_ANNOTATED_PARAMETER_OVERRIDES_NOTNULL" value="true" />
<option name="REPORT_NOT_ANNOTATED_GETTER" value="true" />
<option name="REPORT_NOT_ANNOTATED_SETTER_PARAMETER" value="true" />
<option name="REPORT_ANNOTATION_NOT_PROPAGATED_TO_OVERRIDERS" value="true" />
<option name="REPORT_NULLS_PASSED_TO_NON_ANNOTATED_METHOD" value="true" />
</inspection_tool>
<inspection_tool class="UnqualifiedFieldAccess" enabled="true" level="ERROR" enabled_by_default="true" editorAttributes="ERRORS_ATTRIBUTES" />
</profile>
</component>
</component>

@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=17.0.8.1-librca
java=8.0.382-librca

@ -0,0 +1 @@
java-baseline=8

@ -4,7 +4,6 @@
https://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.

@ -1,4 +1,4 @@
= Spring Boot image:https://ci.spring.io/api/v1/teams/spring-boot/pipelines/spring-boot-3.2.x/jobs/build/badge["Build Status", link="https://ci.spring.io/teams/spring-boot/pipelines/spring-boot-3.2.x?groups=Build"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Gradle Enterprise", link="https://ge.spring.io/scans?&search.rootProjectNames=Spring%20Boot%20Build&search.rootProjectNames=spring-boot-build"]
= Spring Boot image:https://ci.spring.io/api/v1/teams/spring-boot/pipelines/spring-boot-2.7.x/jobs/build/badge["Build Status", link="https://ci.spring.io/teams/spring-boot/pipelines/spring-boot-2.7.x?groups=Build"] image:https://badges.gitter.im/Join Chat.svg["Chat",link="https://gitter.im/spring-projects/spring-boot?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"] image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Gradle Enterprise", link="https://ge.spring.io/scans?&search.rootProjectNames=Spring%20Boot%20Build&search.rootProjectNames=spring-boot-build"]
:docs: https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference
:github: https://github.com/spring-projects/spring-boot
@ -10,7 +10,6 @@ We also provide a command-line tool that runs Spring scripts.
Our primary goals are:
* Provide a radically faster and widely accessible getting started experience for all Spring development.
* Be opinionated, but get out of the way quickly as requirements start to diverge from the defaults.
* Provide a range of non-functional features common to large classes of projects (for example, embedded servers, security, metrics, health checks, externalized configuration).
@ -76,7 +75,7 @@ We like to know the Spring Boot version, operating system, and JVM version you'r
== Building from Source
You don't need to build from source to use Spring Boot (binaries in https://repo.spring.io[repo.spring.io]), but if you want to try out the latest and greatest, Spring Boot can be built and published to your local Maven cache using the https://docs.gradle.org/current/userguide/gradle_wrapper.html[Gradle wrapper].
You also need JDK 17.
You also need JDK 1.8.
[indent=0]
----
@ -126,6 +125,12 @@ For example, if you want to get started using Spring and JPA for database access
=== spring-boot-cli
The Spring command-line application compiles and runs Groovy source, allowing you to write the absolute minimum amount of code to get an application running.
Spring CLI can also watch files, automatically recompiling and restarting when they change.
=== spring-boot-actuator
Actuator endpoints let you monitor and interact with your application.
Spring Boot Actuator provides the infrastructure required for actuator endpoints.
@ -165,6 +170,12 @@ Developer tools are automatically disabled when running a fully packaged applica
== Samples
Groovy samples for use with the command line application are available in link:spring-boot-project/spring-boot-cli/samples[spring-boot-cli/samples].
To run the CLI samples, type `spring run <sample>.groovy` from the samples directory.
== Guides
The https://spring.io/[spring.io] site contains several guides that show how to use Spring Boot step-by-step:

@ -6,8 +6,6 @@ plugins {
description = "Spring Boot Build"
defaultTasks 'build'
nohttp {

@ -2,7 +2,6 @@ plugins {
id "java-gradle-plugin"
id "io.spring.javaformat" version "${javaFormatVersion}"
id "checkstyle"
id "eclipse"
}
repositories {
@ -10,19 +9,18 @@ repositories {
gradlePluginPortal()
}
sourceCompatibility = 17
targetCompatibility = 17
sourceCompatibility = 1.8
targetCompatibility = 1.8
def versions = [:]
new File(projectDir.parentFile, "gradle.properties").withInputStream {
def properties = new Properties()
properties.load(it)
["assertj", "commonsCodec", "hamcrest", "jackson", "junitJupiter",
"kotlin", "maven"].each {
"kotlin", "maven", "springFramework"].each {
versions[it] = properties[it + "Version"]
}
}
versions["springFramework"] = "6.0.12"
ext.set("versions", versions)
if (versions.springFramework.contains("-")) {
repositories {
@ -35,7 +33,6 @@ dependencies {
checkstyle "io.spring.javaformat:spring-javaformat-checkstyle:${javaFormatVersion}"
implementation(platform("org.springframework:spring-framework-bom:${versions.springFramework}"))
implementation("com.diffplug.gradle:goomph:3.37.2")
implementation("com.fasterxml.jackson.core:jackson-databind:${versions.jackson}")
implementation("com.gradle:gradle-enterprise-gradle-plugin:3.12.1")
implementation("com.tngtech.archunit:archunit:1.0.0")
@ -59,7 +56,7 @@ dependencies {
}
checkstyle {
toolVersion = "10.12.4"
toolVersion = 9.3
}
gradlePlugin {
@ -112,10 +109,6 @@ gradlePlugin {
id = "org.springframework.boot.optional-dependencies"
implementationClass = "org.springframework.boot.build.optional.OptionalDependenciesPlugin"
}
processedAnnotationsPlugin {
id = "org.springframework.boot.processed-annotations"
implementationClass = "org.springframework.boot.build.processors.ProcessedAnnotationsPlugin"
}
starterPlugin {
id = "org.springframework.boot.starter"
implementationClass = "org.springframework.boot.build.starters.StarterPlugin"
@ -130,10 +123,3 @@ gradlePlugin {
test {
useJUnitPlatform()
}
eclipse.classpath.file.whenMerged {
def jreEntry = entries.find { it.path.contains("org.eclipse.jdt.launching.JRE_CONTAINER") }
jreEntry.entryAttributes['module'] = 'true'
jreEntry.entryAttributes['limit-modules'] = 'java.base'
}

@ -106,10 +106,10 @@ class AsciidoctorConventions {
configureForkOptions(asciidoctorTask);
asciidoctorTask.baseDirFollowsSourceDir();
createSyncDocumentationSourceTask(project, asciidoctorTask);
if (asciidoctorTask instanceof AsciidoctorTask task) {
boolean pdf = task.getName().toLowerCase().contains("pdf");
if (asciidoctorTask instanceof AsciidoctorTask) {
boolean pdf = asciidoctorTask.getName().toLowerCase().contains("pdf");
String backend = (!pdf) ? "spring-html" : "spring-pdf";
task.outputOptions((outputOptions) -> outputOptions.backends(backend));
((AsciidoctorTask) asciidoctorTask).outputOptions((outputOptions) -> outputOptions.backends(backend));
}
}
@ -134,7 +134,7 @@ class AsciidoctorConventions {
private String determineGitHubTag(Project project) {
String version = "v" + project.getVersion();
return (version.endsWith("-SNAPSHOT")) ? "main" : version;
return (version.endsWith("-SNAPSHOT")) ? "2.7.x" : version;
}
private void configureOptions(AbstractAsciidoctorTask asciidoctorTask) {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,8 +47,6 @@ public class ConventionsPlugin implements Plugin<Project> {
new MavenPublishingConventions().apply(project);
new AsciidoctorConventions().apply(project);
new KotlinConventions().apply(project);
new WarConventions().apply(project);
new EclipseConventions().apply(project);
}
}

@ -1,69 +0,0 @@
/*
* Copyright 2023-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build;
import org.gradle.api.Project;
import org.gradle.plugins.ide.api.XmlFileContentMerger;
import org.gradle.plugins.ide.eclipse.EclipsePlugin;
import org.gradle.plugins.ide.eclipse.model.Classpath;
import org.gradle.plugins.ide.eclipse.model.ClasspathEntry;
import org.gradle.plugins.ide.eclipse.model.EclipseClasspath;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
import org.gradle.plugins.ide.eclipse.model.Library;
/**
* Conventions that are applied in the presence of the {@link EclipsePlugin} to work
* around buildship issue {@code #1238}.
*
* @author Phillip Webb
*/
class EclipseConventions {
void apply(Project project) {
project.getPlugins().withType(EclipsePlugin.class, (eclipse) -> {
EclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);
eclipseModel.classpath(this::configureClasspath);
});
}
private void configureClasspath(EclipseClasspath classpath) {
classpath.file(this::configureClasspathFile);
}
private void configureClasspathFile(XmlFileContentMerger merger) {
merger.whenMerged((content) -> {
if (content instanceof Classpath classpath) {
classpath.getEntries().removeIf(this::isKotlinPluginContributedBuildDirectory);
}
});
}
private boolean isKotlinPluginContributedBuildDirectory(ClasspathEntry entry) {
return (entry instanceof Library library) && isKotlinPluginContributedBuildDirectory(library.getPath())
&& isTest(library);
}
private boolean isKotlinPluginContributedBuildDirectory(String path) {
return path.contains("/main") && (path.contains("/build/classes/") || path.contains("/build/resources/"));
}
private boolean isTest(Library library) {
Object value = library.getEntryAttributes().get("test");
return (value instanceof String string && Boolean.parseBoolean(string));
}
}

@ -47,7 +47,6 @@ import org.gradle.api.tasks.bundling.Jar;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.api.tasks.javadoc.Javadoc;
import org.gradle.api.tasks.testing.Test;
import org.gradle.external.javadoc.CoreJavadocOptions;
import org.springframework.boot.build.architecture.ArchitecturePlugin;
import org.springframework.boot.build.classpath.CheckClasspathForProhibitedDependencies;
@ -61,7 +60,7 @@ import org.springframework.util.StringUtils;
* plugin is applied:
*
* <ul>
* <li>The project is configured with source and target compatibility of 17
* <li>The project is configured with source and target compatibility of 1.8
* <li>{@link SpringJavaFormatPlugin Spring Java Format}, {@link CheckstylePlugin
* Checkstyle}, {@link TestFailuresPlugin Test Failures}, and {@link ArchitecturePlugin
* Architecture} plugins are applied
@ -79,9 +78,9 @@ import org.springframework.util.StringUtils;
* {@link JavaPlugin} applied
* <li>{@link JavaCompile}, {@link Javadoc}, and {@link Format} tasks are configured to
* use UTF-8 encoding
* <li>{@link JavaCompile} tasks are configured to:
* <li>{@link JavaCompile} tasks are configured to use {@code -parameters}.
* <li>When building with Java 8, {@link JavaCompile} tasks are also configured to:
* <ul>
* <li>Use {@code -parameters}.
* <li>Treat warnings as errors
* <li>Enable {@code unchecked}, {@code deprecation}, {@code rawtypes}, and {@code varags}
* warnings
@ -107,7 +106,7 @@ import org.springframework.util.StringUtils;
*/
class JavaConventions {
private static final String SOURCE_AND_TARGET_COMPATIBILITY = "17";
private static final String SOURCE_AND_TARGET_COMPATIBILITY = "1.8";
void apply(Project project) {
project.getPlugins().withType(JavaBasePlugin.class, (java) -> {
@ -200,12 +199,7 @@ class JavaConventions {
}
private void configureJavadocConventions(Project project) {
project.getTasks().withType(Javadoc.class, (javadoc) -> {
CoreJavadocOptions options = (CoreJavadocOptions) javadoc.getOptions();
options.source("17");
options.encoding("UTF-8");
options.addStringOption("Xdoclint:none", "-quiet");
});
project.getTasks().withType(Javadoc.class, (javadoc) -> javadoc.getOptions().source("1.8").encoding("UTF-8"));
}
private void configureJavaConventions(Project project) {
@ -223,15 +217,15 @@ class JavaConventions {
compile.setSourceCompatibility(SOURCE_AND_TARGET_COMPATIBILITY);
compile.setTargetCompatibility(SOURCE_AND_TARGET_COMPATIBILITY);
}
else if (buildingWithJava17(project)) {
else if (buildingWithJava8(project)) {
args.addAll(Arrays.asList("-Werror", "-Xlint:unchecked", "-Xlint:deprecation", "-Xlint:rawtypes",
"-Xlint:varargs"));
}
});
}
private boolean buildingWithJava17(Project project) {
return !project.hasProperty("toolchainVersion") && JavaVersion.current() == JavaVersion.VERSION_17;
private boolean buildingWithJava8(Project project) {
return !project.hasProperty("toolchainVersion") && JavaVersion.current() == JavaVersion.VERSION_1_8;
}
private void configureSpringJavaFormat(Project project) {
@ -258,10 +252,11 @@ class JavaConventions {
.matching((configuration) -> configuration.getName().endsWith("Classpath")
|| JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME.equals(configuration.getName()))
.all((configuration) -> configuration.extendsFrom(dependencyManagement));
Dependency springBootParent = project.getDependencies()
.enforcedPlatform(project.getDependencies()
.project(Collections.singletonMap("path", ":spring-boot-project:spring-boot-parent")));
dependencyManagement.getDependencies().add(springBootParent);
String path = project.getName().contains("spring-boot-starter")
? ":spring-boot-project:spring-boot-dependencies" : ":spring-boot-project:spring-boot-parent";
Dependency dependency = project.getDependencies()
.enforcedPlatform(project.getDependencies().project(Collections.singletonMap("path", path)));
dependencyManagement.getDependencies().add(dependency);
project.getPlugins()
.withType(OptionalDependenciesPlugin.class,
(optionalDependencies) -> configurations

@ -30,8 +30,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile;
* <ul>
* <li>{@link KotlinCompile} tasks are configured to:
* <ul>
* <li>Use {@code apiVersion} and {@code languageVersion} 1.7.
* <li>Use {@code jvmTarget} 17.
* <li>Use {@code apiVersion} and {@code languageVersion} 1.3.
* <li>Use {@code jvmTarget} 1.8.
* <li>Treat all warnings as errors
* <li>Suppress version warnings
* </ul>
@ -51,9 +51,9 @@ class KotlinConventions {
private void configure(KotlinCompile compile) {
KotlinJvmOptions kotlinOptions = compile.getKotlinOptions();
kotlinOptions.setApiVersion("1.7");
kotlinOptions.setLanguageVersion("1.7");
kotlinOptions.setJvmTarget("17");
kotlinOptions.setApiVersion("1.3");
kotlinOptions.setLanguageVersion("1.3");
kotlinOptions.setJvmTarget("1.8");
kotlinOptions.setAllWarningsAsErrors(true);
List<String> freeCompilerArgs = new ArrayList<>(compile.getKotlinOptions().getFreeCompilerArgs());
freeCompilerArgs.add("-Xsuppress-version-warnings");

@ -1,60 +0,0 @@
/*
* Copyright 2023-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build;
import java.util.ArrayList;
import java.util.List;
import org.gradle.api.JavaVersion;
import org.gradle.api.Project;
import org.gradle.api.internal.IConventionAware;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.plugins.ide.eclipse.EclipseWtpPlugin;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
import org.gradle.plugins.ide.eclipse.model.Facet;
/**
* Conventions that are applied in the presence of the {WarPlugin}. When the plugin is
* applied:
* <ul>
* <li>Update Eclipse WTP Plugin facets to use Servlet 5.0</li>
* </ul>
*
* @author Phillip Webb
*/
public class WarConventions {
void apply(Project project) {
project.getPlugins().withType(EclipseWtpPlugin.class, (wtp) -> {
project.getTasks().getByName(EclipseWtpPlugin.ECLIPSE_WTP_FACET_TASK_NAME).doFirst((task) -> {
EclipseModel eclipseModel = project.getExtensions().getByType(EclipseModel.class);
((IConventionAware) eclipseModel.getWtp().getFacet()).getConventionMapping()
.map("facets", () -> getFacets(project));
});
});
}
private List<Facet> getFacets(Project project) {
JavaVersion javaVersion = project.getExtensions().getByType(JavaPluginExtension.class).getSourceCompatibility();
List<Facet> facets = new ArrayList<>();
facets.add(new Facet(Facet.FacetType.fixed, "jst.web", null));
facets.add(new Facet(Facet.FacetType.installed, "jst.web", "5.0"));
facets.add(new Facet(Facet.FacetType.installed, "jst.java", javaVersion.toString()));
return facets;
}
}

@ -18,6 +18,7 @@ package org.springframework.boot.build.architecture;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.List;
@ -71,19 +72,20 @@ public abstract class ArchitectureCheck extends DefaultTask {
allBeanPostProcessorBeanMethodsShouldBeStaticAndHaveParametersThatWillNotCausePrematureInitialization(),
allBeanFactoryPostProcessorBeanMethodsShouldBeStaticAndHaveNoParameters(),
noClassesShouldCallStepVerifierStepVerifyComplete(),
noClassesShouldConfigureDefaultStepVerifierTimeout(), noClassesShouldCallCollectorsToList());
getRuleDescriptions().set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).toList()));
noClassesShouldConfigureDefaultStepVerifierTimeout());
getRuleDescriptions()
.set(getRules().map((rules) -> rules.stream().map(ArchRule::getDescription).collect(Collectors.toList())));
}
@TaskAction
void checkArchitecture() throws IOException {
JavaClasses javaClasses = new ClassFileImporter()
.importPaths(this.classes.getFiles().stream().map(File::toPath).toList());
.importPaths(this.classes.getFiles().stream().map(File::toPath).collect(Collectors.toList()));
List<EvaluationResult> violations = getRules().get()
.stream()
.map((rule) -> rule.evaluate(javaClasses))
.filter(EvaluationResult::hasViolation)
.toList();
.collect(Collectors.toList());
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
outputFile.getParentFile().mkdirs();
if (!violations.isEmpty()) {
@ -92,8 +94,8 @@ public abstract class ArchitectureCheck extends DefaultTask {
report.append(violation.getFailureReport().toString());
report.append(String.format("%n"));
}
Files.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
Files.write(outputFile.toPath(), report.toString().getBytes(StandardCharsets.UTF_8),
StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
throw new GradleException("Architecture check failed. See '" + outputFile + "' for details.");
}
else {
@ -124,7 +126,7 @@ public abstract class ArchitectureCheck extends DefaultTask {
.not(Predicates.assignableTo("org.springframework.beans.factory.ObjectProvider")
.or(Predicates.assignableTo("org.springframework.context.ApplicationContext"))
.or(Predicates.assignableTo("org.springframework.core.env.Environment")));
return new ArchCondition<>("not have parameters that will cause eager initialization") {
return new ArchCondition<JavaMethod>("not have parameters that will cause eager initialization") {
@Override
public void check(JavaMethod item, ConditionEvents events) {
@ -155,7 +157,7 @@ public abstract class ArchitectureCheck extends DefaultTask {
}
private ArchCondition<JavaMethod> haveNoParameters() {
return new ArchCondition<>("have no parameters") {
return new ArchCondition<JavaMethod>("have no parameters") {
@Override
public void check(JavaMethod item, ConditionEvents events) {
@ -183,13 +185,6 @@ public abstract class ArchitectureCheck extends DefaultTask {
.because("expectComplete().verify(Duration) should be used instead");
}
private ArchRule noClassesShouldCallCollectorsToList() {
return ArchRuleDefinition.noClasses()
.should()
.callMethod(Collectors.class, "toList")
.because("java.util.stream.Stream.toList() should be used instead");
}
public void setClasses(FileCollection classes) {
this.classes = classes;
}

@ -23,6 +23,9 @@ import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
@ -40,13 +43,13 @@ import org.gradle.api.tasks.TaskAction;
import org.springframework.asm.ClassReader;
import org.springframework.asm.Opcodes;
import org.springframework.core.CollectionFactory;
import org.springframework.util.StringUtils;
/**
* A {@link Task} for generating metadata describing a project's auto-configuration
* classes.
*
* @author Andy Wilkinson
* @author Scott Frederick
*/
public class AutoConfigurationMetadata extends DefaultTask {
@ -57,6 +60,11 @@ public class AutoConfigurationMetadata extends DefaultTask {
private File outputFile;
public AutoConfigurationMetadata() {
getInputs()
.file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
"META-INF/spring.factories"))
.withPathSensitivity(PathSensitivity.RELATIVE)
.withPropertyName("spring.factories");
getInputs()
.file((Callable<File>) () -> new File(this.sourceSet.getOutput().getResourcesDir(),
"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports"))
@ -92,7 +100,9 @@ public class AutoConfigurationMetadata extends DefaultTask {
private Properties readAutoConfiguration() throws IOException {
Properties autoConfiguration = CollectionFactory.createSortedProperties(true);
List<String> classNames = readAutoConfigurationsFile();
Set<String> classNames = new LinkedHashSet<>();
classNames.addAll(readSpringFactories());
classNames.addAll(readAutoConfigurationsFile());
Set<String> publicClassNames = new LinkedHashSet<>();
for (String className : classNames) {
File classFile = findClassFile(className);
@ -111,6 +121,21 @@ public class AutoConfigurationMetadata extends DefaultTask {
return autoConfiguration;
}
/**
* Reads auto-configurations from META-INF/spring.factories.
* @return auto-configurations
*/
private Set<String> readSpringFactories() throws IOException {
File file = new File(this.sourceSet.getOutput().getResourcesDir(), "META-INF/spring.factories");
if (!file.exists()) {
return Collections.emptySet();
}
Properties springFactories = readSpringFactories(file);
String enableAutoConfiguration = springFactories
.getProperty("org.springframework.boot.autoconfigure.EnableAutoConfiguration");
return StringUtils.commaDelimitedListToSet(enableAutoConfiguration);
}
/**
* Reads auto-configurations from
* META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports.
@ -122,17 +147,29 @@ public class AutoConfigurationMetadata extends DefaultTask {
if (!file.exists()) {
return Collections.emptyList();
}
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
return reader.lines().map(this::stripComment).filter((line) -> !line.isEmpty()).toList();
// Nearly identical copy of
// org.springframework.boot.context.annotation.ImportCandidates.load
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)))) {
List<String> autoConfigurations = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
line = stripComment(line);
line = line.trim();
if (line.isEmpty()) {
continue;
}
autoConfigurations.add(line);
}
return autoConfigurations;
}
}
private String stripComment(String line) {
int commentStart = line.indexOf(COMMENT_START);
if (commentStart == -1) {
return line.trim();
return line;
}
return line.substring(0, commentStart).trim();
return line.substring(0, commentStart);
}
private File findClassFile(String className) {
@ -146,4 +183,12 @@ public class AutoConfigurationMetadata extends DefaultTask {
return null;
}
private Properties readSpringFactories(File file) throws IOException {
Properties springFactories = new Properties();
try (Reader in = new FileReader(file)) {
springFactories.load(in);
}
return springFactories;
}
}

@ -42,6 +42,7 @@ import org.gradle.api.tasks.SourceSet;
import org.springframework.boot.build.DeployedPlugin;
import org.springframework.boot.build.architecture.ArchitectureCheck;
import org.springframework.boot.build.architecture.ArchitecturePlugin;
import org.springframework.boot.build.context.properties.ConfigurationPropertiesPlugin;
/**
* {@link Plugin} for projects that define auto-configuration. When applied, the plugin
@ -49,6 +50,7 @@ import org.springframework.boot.build.architecture.ArchitecturePlugin;
* applied it:
*
* <ul>
* <li>Applies the {@link ConfigurationPropertiesPlugin}.
* <li>Adds a dependency on the auto-configuration annotation processor.
* <li>Defines a task that produces metadata describing the auto-configuration. The
* metadata is made available as an artifact in the {@code autoConfigurationMetadata}
@ -77,6 +79,7 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
public void apply(Project project) {
project.getPlugins().apply(DeployedPlugin.class);
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
project.getPlugins().apply(ConfigurationPropertiesPlugin.class);
Configuration annotationProcessors = project.getConfigurations()
.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);
annotationProcessors.getDependencies()
@ -127,7 +130,7 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
}
private ArchCondition<JavaClass> beListedInAutoConfigurationImports(Provider<AutoConfigurationImports> imports) {
return new ArchCondition<>("be listed in " + AUTO_CONFIGURATION_IMPORTS_PATH) {
return new ArchCondition<JavaClass>("be listed in " + AUTO_CONFIGURATION_IMPORTS_PATH) {
@Override
public void check(JavaClass item, ConditionEvents events) {
@ -154,7 +157,16 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
});
}
private static record AutoConfigurationImports(Path importsFile, List<String> imports) {
private static final class AutoConfigurationImports {
private final Path importsFile;
private final List<String> imports;
private AutoConfigurationImports(Path importsFile, List<String> imports) {
this.importsFile = importsFile;
this.imports = imports;
}
}

@ -26,6 +26,7 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.xml.parsers.DocumentBuilderFactory;
@ -105,7 +106,7 @@ public class BomExtension {
}
public void library(String name, Action<LibraryHandler> action) {
library(name, null, action);
this.library(name, null, action);
}
public void library(String name, String version, Action<LibraryHandler> action) {
@ -318,8 +319,8 @@ public class BomExtension {
public void setModules(List<Object> modules) {
this.modules = modules.stream()
.map((input) -> (input instanceof Module module) ? module : new Module((String) input))
.toList();
.map((input) -> (input instanceof Module) ? (Module) input : new Module((String) input))
.collect(Collectors.toList());
}
public void setImports(List<String> imports) {
@ -333,8 +334,9 @@ public class BomExtension {
public Object methodMissing(String name, Object args) {
if (args instanceof Object[] && ((Object[]) args).length == 1) {
Object arg = ((Object[]) args)[0];
if (arg instanceof Closure<?> closure) {
if (arg instanceof Closure) {
ModuleHandler moduleHandler = new ModuleHandler();
Closure<?> closure = (Closure<?>) arg;
closure.setResolveStrategy(Closure.DELEGATE_FIRST);
closure.setDelegate(moduleHandler);
closure.call(moduleHandler);

@ -268,8 +268,9 @@ public class BomPlugin implements Plugin<Project> {
private Node findChild(Node parent, String name) {
for (Object child : parent.children()) {
if (child instanceof Node node) {
if ((node.name() instanceof QName qname) && name.equals(qname.getLocalPart())) {
if (child instanceof Node) {
Node node = (Node) child;
if ((node.name() instanceof QName) && name.equals(((QName) node.name()).getLocalPart())) {
return node;
}
if (name.equals(node.name())) {
@ -282,12 +283,17 @@ public class BomPlugin implements Plugin<Project> {
@SuppressWarnings("unchecked")
private List<Node> findChildren(Node parent, String name) {
return parent.children().stream().filter((child) -> isNodeWithName(child, name)).toList();
return (List<Node>) parent.children()
.stream()
.filter((child) -> isNodeWithName(child, name))
.collect(Collectors.toList());
}
private boolean isNodeWithName(Object candidate, String name) {
if (candidate instanceof Node node) {
if ((node.name() instanceof QName qname) && name.equals(qname.getLocalPart())) {
if (candidate instanceof Node) {
Node node = (Node) candidate;
if ((node.name() instanceof QName) && name.equals(((QName) node.name()).getLocalPart())) {
return true;
}
if (name.equals(node.name())) {

@ -21,6 +21,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
import org.gradle.api.internal.tasks.userinput.UserInputHandler;
@ -51,7 +52,7 @@ public final class InteractiveUpgradeResolver implements UpgradeResolver {
}
List<LibraryWithVersionOptions> libraryUpdates = this.libraryUpdateResolver
.findLibraryUpdates(librariesToUpgrade, librariesByName);
return libraryUpdates.stream().map(this::resolveUpgrade).filter(Objects::nonNull).toList();
return libraryUpdates.stream().map(this::resolveUpgrade).filter(Objects::nonNull).collect(Collectors.toList());
}
private Upgrade resolveUpgrade(LibraryWithVersionOptions libraryWithVersionOptions) {

@ -58,18 +58,7 @@ final class MavenMetadataVersionResolver implements VersionResolver {
MavenMetadataVersionResolver(RestTemplate restTemplate, Collection<URI> repositoryUrls) {
this.rest = restTemplate;
this.repositoryUrls = normalize(repositoryUrls);
}
private Collection<URI> normalize(Collection<URI> uris) {
return uris.stream().map(this::normalize).toList();
}
private URI normalize(URI uri) {
if ("/".equals(uri.getPath())) {
return uri;
}
return URI.create(uri.toString() + "/");
this.repositoryUrls = repositoryUrls;
}
@Override

@ -24,6 +24,7 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
@ -61,7 +62,7 @@ class MultithreadedLibraryUpdateResolver implements LibraryUpdateResolver {
.map((library) -> executorService.submit(
() -> this.delegate.findLibraryUpdates(Collections.singletonList(library), librariesByName)))
.flatMap(this::getResult)
.toList();
.collect(Collectors.toList());
}
finally {
executorService.shutdownNow();

@ -19,11 +19,13 @@ package org.springframework.boot.build.bom.bomr;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.function.BiPredicate;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -94,14 +96,19 @@ class StandardLibraryUpdateResolver implements LibraryUpdateResolver {
getLaterVersionsForModule(group.getId(), plugin, library));
}
}
return moduleVersions.values()
List<DependencyVersion> allVersions = moduleVersions.values()
.stream()
.flatMap(SortedSet::stream)
.distinct()
.filter((dependencyVersion) -> this.predicate.test(library, dependencyVersion))
.map((version) -> (VersionOption) new VersionOption.ResolvedVersionOption(version,
.collect(Collectors.toList());
if (allVersions.isEmpty()) {
return Collections.emptyList();
}
return allVersions.stream()
.map((version) -> new VersionOption.ResolvedVersionOption(version,
getMissingModules(moduleVersions, version)))
.toList();
.collect(Collectors.toList());
}
private List<String> getMissingModules(Map<String, SortedSet<DependencyVersion>> moduleVersions,

@ -17,6 +17,7 @@
package org.springframework.boot.build.bom.bomr;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
@ -41,7 +42,7 @@ class UpgradeApplicator {
}
Path apply(Upgrade upgrade) throws IOException {
String buildFileContents = Files.readString(this.buildFile);
String buildFileContents = new String(Files.readAllBytes(this.buildFile), StandardCharsets.UTF_8);
Matcher matcher = Pattern.compile("library\\(\"" + upgrade.getLibrary().getName() + "\", \"(.+)\"\\)")
.matcher(buildFileContents);
if (!matcher.find()) {
@ -67,7 +68,7 @@ class UpgradeApplicator {
private void updateGradleProperties(Upgrade upgrade, String version) throws IOException {
String property = version.substring(2, version.length() - 1);
String gradlePropertiesContents = Files.readString(this.gradleProperties);
String gradlePropertiesContents = new String(Files.readAllBytes(this.gradleProperties), StandardCharsets.UTF_8);
String modified = gradlePropertiesContents.replace(
property + "=" + upgrade.getLibrary().getVersion().getVersion(), property + "=" + upgrade.getVersion());
overwrite(this.gradleProperties, modified);
@ -81,7 +82,8 @@ class UpgradeApplicator {
}
private void overwrite(Path target, String content) throws IOException {
Files.writeString(target, content, StandardOpenOption.WRITE, StandardOpenOption.TRUNCATE_EXISTING);
Files.write(target, content.getBytes(StandardCharsets.UTF_8), StandardOpenOption.WRITE,
StandardOpenOption.TRUNCATE_EXISTING);
}
}

@ -30,6 +30,7 @@ import java.util.Set;
import java.util.function.BiPredicate;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;
@ -260,7 +261,10 @@ public abstract class UpgradeDependencies extends DefaultTask {
}
private List<Library> matchingLibraries() {
List<Library> matchingLibraries = this.bom.getLibraries().stream().filter(this::eligible).toList();
List<Library> matchingLibraries = this.bom.getLibraries()
.stream()
.filter(this::eligible)
.collect(Collectors.toList());
if (matchingLibraries.isEmpty()) {
throw new InvalidUserDataException("No libraries to upgrade");
}

@ -24,6 +24,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.HttpClientErrorException.Forbidden;
@ -62,8 +63,8 @@ final class StandardGitHubRepository implements GitHubRepository {
return (Integer) response.getBody().get("number");
}
catch (RestClientException ex) {
if (ex instanceof Forbidden forbidden) {
System.out.println("Received 403 response with headers " + forbidden.getResponseHeaders());
if (ex instanceof Forbidden) {
System.out.println("Received 403 response with headers " + ((Forbidden) ex).getResponseHeaders());
}
throw ex;
}
@ -93,7 +94,8 @@ final class StandardGitHubRepository implements GitHubRepository {
@SuppressWarnings({ "rawtypes", "unchecked" })
private <T> List<T> get(String name, Function<Map<String, Object>, T> mapper) {
ResponseEntity<List> response = this.rest.getForEntity(name, List.class);
return ((List<Map<String, Object>>) response.getBody()).stream().map(mapper).toList();
List<Map<String, Object>> body = response.getBody();
return body.stream().map(mapper).collect(Collectors.toList());
}
private static void sleep(Duration duration) {

@ -33,8 +33,8 @@ abstract class AbstractDependencyVersion implements DependencyVersion {
@Override
public int compareTo(DependencyVersion other) {
ComparableVersion otherComparable = (other instanceof AbstractDependencyVersion otherVersion)
? otherVersion.comparableVersion : new ComparableVersion(other.toString());
ComparableVersion otherComparable = (other instanceof AbstractDependencyVersion)
? ((AbstractDependencyVersion) other).comparableVersion : new ComparableVersion(other.toString());
return this.comparableVersion.compareTo(otherComparable);
}

@ -16,7 +16,6 @@
package org.springframework.boot.build.bom.bomr.version;
import java.util.Objects;
import java.util.Optional;
import org.apache.maven.artifact.versioning.ArtifactVersion;
@ -122,21 +121,6 @@ class ArtifactVersionDependencyVersion extends AbstractDependencyVersion {
return sameMajorMinorIncremental(((ArtifactVersionDependencyVersion) candidate).artifactVersion);
}
@Override
public int compareTo(DependencyVersion other) {
if (other instanceof ArtifactVersionDependencyVersion otherArtifactDependencyVersion) {
ArtifactVersion otherArtifactVersion = otherArtifactDependencyVersion.artifactVersion;
if ((!Objects.equals(this.artifactVersion.getQualifier(), otherArtifactVersion.getQualifier()))
&& "snapshot".equalsIgnoreCase(otherArtifactVersion.getQualifier())
&& otherArtifactVersion.getMajorVersion() == this.artifactVersion.getMajorVersion()
&& otherArtifactVersion.getMinorVersion() == this.artifactVersion.getMinorVersion()
&& otherArtifactVersion.getIncrementalVersion() == this.artifactVersion.getIncrementalVersion()) {
return 1;
}
}
return super.compareTo(other);
}
@Override
public String toString() {
return this.artifactVersion.toString();
@ -145,8 +129,8 @@ class ArtifactVersionDependencyVersion extends AbstractDependencyVersion {
protected Optional<ArtifactVersionDependencyVersion> extractArtifactVersionDependencyVersion(
DependencyVersion other) {
ArtifactVersionDependencyVersion artifactVersion = null;
if (other instanceof ArtifactVersionDependencyVersion otherVersion) {
artifactVersion = otherVersion;
if (other instanceof ArtifactVersionDependencyVersion) {
artifactVersion = (ArtifactVersionDependencyVersion) other;
}
return Optional.ofNullable(artifactVersion);
}

@ -48,9 +48,10 @@ final class ReleaseTrainDependencyVersion implements DependencyVersion {
@Override
public int compareTo(DependencyVersion other) {
if (!(other instanceof ReleaseTrainDependencyVersion otherReleaseTrain)) {
if (!(other instanceof ReleaseTrainDependencyVersion)) {
return -1;
}
ReleaseTrainDependencyVersion otherReleaseTrain = (ReleaseTrainDependencyVersion) other;
int comparison = this.releaseTrain.compareTo(otherReleaseTrain.releaseTrain);
if (comparison != 0) {
return comparison;
@ -109,10 +110,11 @@ final class ReleaseTrainDependencyVersion implements DependencyVersion {
if (other instanceof CalendarVersionDependencyVersion) {
return false;
}
if (other instanceof ReleaseTrainDependencyVersion otherReleaseTrain) {
return otherReleaseTrain.releaseTrain.equals(this.releaseTrain);
if (!(other instanceof ReleaseTrainDependencyVersion)) {
return true;
}
return true;
ReleaseTrainDependencyVersion otherReleaseTrain = (ReleaseTrainDependencyVersion) other;
return otherReleaseTrain.releaseTrain.equals(this.releaseTrain);
}
@Override

@ -34,7 +34,6 @@ import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
@ -69,10 +68,9 @@ public class CheckClasspathForConflicts extends DefaultTask {
for (File file : this.classpath) {
if (file.isDirectory()) {
Path root = file.toPath();
try (Stream<Path> pathStream = Files.walk(root)) {
pathStream.filter(Files::isRegularFile)
.forEach((entry) -> classpathContents.add(root.relativize(entry).toString(), root.toString()));
}
Files.walk(root)
.filter(Files::isRegularFile)
.forEach((entry) -> classpathContents.add(root.relativize(entry).toString(), root.toString()));
}
else {
try (JarFile jar = new JarFile(file)) {

@ -79,12 +79,6 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
if (group.equals("javax.money")) {
return false;
}
if (group.equals("org.codehaus.groovy")) {
return true;
}
if (group.equals("org.eclipse.jetty.toolchain")) {
return true;
}
if (group.startsWith("javax")) {
return true;
}
@ -100,9 +94,6 @@ public class CheckClasspathForProhibitedDependencies extends DefaultTask {
if (group.equals("org.apache.geronimo.specs")) {
return true;
}
if (group.equals("com.sun.activation")) {
return true;
}
return false;
}

@ -88,8 +88,8 @@ public class CheckClasspathForUnnecessaryExclusions extends DefaultTask {
}
private void processDependency(Dependency dependency) {
if (dependency instanceof ModuleDependency moduleDependency) {
processDependency(moduleDependency);
if (dependency instanceof ModuleDependency) {
processDependency((ModuleDependency) dependency);
}
}

@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
@ -94,7 +95,7 @@ public class CheckAdditionalSpringConfigurationMetadata extends SourceTask {
@SuppressWarnings("unchecked")
private void check(String key, Map<String, Object> json, Analysis analysis) {
List<Map<String, Object>> groups = (List<Map<String, Object>>) json.get(key);
List<String> names = groups.stream().map((group) -> (String) group.get("name")).toList();
List<String> names = groups.stream().map((group) -> (String) group.get("name")).collect(Collectors.toList());
List<String> sortedNames = sortedCopy(names);
for (int i = 0; i < names.size(); i++) {
String actual = names.get(i);

@ -25,6 +25,7 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.JsonMappingException;
@ -153,7 +154,9 @@ public class CheckSpringConfigurationMetadata extends DefaultTask {
else {
lines.add("The following properties have no description:");
lines.add("");
lines.addAll(this.propertiesWithNoDescription.stream().map((line) -> "\t" + line).toList());
lines.addAll(this.propertiesWithNoDescription.stream()
.map((line) -> "\t" + line)
.collect(Collectors.toList()));
}
lines.add("");
return lines.iterator();

@ -33,7 +33,6 @@ import org.gradle.api.tasks.TaskProvider;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
import org.springframework.boot.build.processors.ProcessedAnnotationsPlugin;
import org.springframework.util.StringUtils;
/**
@ -76,7 +75,7 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
configureConfigurationPropertiesAnnotationProcessor(project);
addConfigurationProcessorDependency(project);
disableIncrementalCompilation(project);
configureAdditionalMetadataLocationsCompilerArgument(project);
registerCheckAdditionalMetadataTask(project);
@ -85,14 +84,13 @@ public class ConfigurationPropertiesPlugin implements Plugin<Project> {
});
}
private void configureConfigurationPropertiesAnnotationProcessor(Project project) {
private void addConfigurationProcessorDependency(Project project) {
Configuration annotationProcessors = project.getConfigurations()
.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME);
annotationProcessors.getDependencies()
.add(project.getDependencies()
.project(Collections.singletonMap("path",
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor")));
project.getPlugins().apply(ProcessedAnnotationsPlugin.class);
}
private void disableIncrementalCompilation(Project project) {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -78,7 +78,6 @@ public class DocumentConfigurationProperties extends DefaultTask {
snippets.add("application-properties.security", "Security Properties", this::securityPrefixes);
snippets.add("application-properties.rsocket", "RSocket Properties", this::rsocketPrefixes);
snippets.add("application-properties.actuator", "Actuator Properties", this::actuatorPrefixes);
snippets.add("application-properties.docker-compose", "Docker Compose Properties", this::dockerComposePrefixes);
snippets.add("application-properties.devtools", "Devtools Properties", this::devtoolsPrefixes);
snippets.add("application-properties.testing", "Testing Properties", this::testingPrefixes);
snippets.writeTo(this.outputDir.toPath());
@ -104,9 +103,7 @@ public class DocumentConfigurationProperties extends DefaultTask {
config.accept("spring.profiles");
config.accept("spring.quartz");
config.accept("spring.reactor");
config.accept("spring.ssl");
config.accept("spring.task");
config.accept("spring.threads");
config.accept("spring.mandatory-file-encoding");
config.accept("info");
config.accept("spring.output.ansi.enabled");
@ -128,13 +125,13 @@ public class DocumentConfigurationProperties extends DefaultTask {
private void dataPrefixes(Config config) {
config.accept("spring.couchbase");
config.accept("spring.cassandra");
config.accept("spring.elasticsearch");
config.accept("spring.h2");
config.accept("spring.influx");
config.accept("spring.ldap");
config.accept("spring.mongodb");
config.accept("spring.neo4j");
config.accept("spring.redis");
config.accept("spring.dao");
config.accept("spring.data");
config.accept("spring.datasource");
@ -171,7 +168,6 @@ public class DocumentConfigurationProperties extends DefaultTask {
prefix.accept("spring.integration");
prefix.accept("spring.jms");
prefix.accept("spring.kafka");
prefix.accept("spring.pulsar");
prefix.accept("spring.rabbitmq");
prefix.accept("spring.hazelcast");
prefix.accept("spring.webservices");
@ -181,11 +177,11 @@ public class DocumentConfigurationProperties extends DefaultTask {
prefix.accept("spring.graphql");
prefix.accept("spring.hateoas");
prefix.accept("spring.http");
prefix.accept("spring.servlet");
prefix.accept("spring.jersey");
prefix.accept("spring.mvc");
prefix.accept("spring.netty");
prefix.accept("spring.resources");
prefix.accept("spring.servlet");
prefix.accept("spring.session");
prefix.accept("spring.web");
prefix.accept("spring.webflux");
@ -215,10 +211,6 @@ public class DocumentConfigurationProperties extends DefaultTask {
prefix.accept("management");
}
private void dockerComposePrefixes(Config prefix) {
prefix.accept("spring.docker.compose");
}
private void devtoolsPrefixes(Config prefix) {
prefix.accept("spring.devtools");
}

@ -21,6 +21,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -105,8 +106,8 @@ public class ApplicationRunner extends DefaultTask {
}
public void normalizeTomcatPort() {
this.normalizations.put("(Tomcat started on port )[\\d]+( \\(http\\))", "$18080$2");
this.normalizations.put("(Tomcat initialized with port )[\\d]+( \\(http\\))", "$18080$2");
this.normalizations.put("(Tomcat started on port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2");
this.normalizations.put("(Tomcat initialized with port\\(s\\): )[\\d]+( \\(http\\))", "$18080$2");
}
public void normalizeLiveReloadPort() {
@ -138,8 +139,10 @@ public class ApplicationRunner extends DefaultTask {
private void awaitLogging(Process process) {
long end = System.currentTimeMillis() + 60000;
String expectedLogging = this.expectedLogging.get();
List<String> outputLines = Collections.emptyList();
while (System.currentTimeMillis() < end) {
for (String line : outputLines()) {
outputLines = outputLines();
for (String line : outputLines) {
if (line.contains(expectedLogging)) {
return;
}
@ -148,7 +151,10 @@ public class ApplicationRunner extends DefaultTask {
throw new IllegalStateException("Process exited before '" + expectedLogging + "' was logged");
}
}
throw new IllegalStateException("'" + expectedLogging + "' was not logged within 60 seconds");
StringBuilder message = new StringBuilder(
"After 60 seconds '" + expectedLogging + "' had not be logged in the following output:\n\n");
outputLines.forEach((line) -> message.append(line).append("\n"));
throw new IllegalStateException(message.toString());
}
private List<String> outputLines() {
@ -176,8 +182,8 @@ public class ApplicationRunner extends DefaultTask {
private List<String> normalize(List<String> lines) {
List<String> normalizedLines = lines;
Map<String, String> normalizations = new HashMap<>(this.normalizations);
normalizations.put("(Starting .* using Java .* with PID [\\d]+ \\().*( started by ).*( in ).*(\\))",
"$1" + this.applicationJar.get() + "$2myuser$3/opt/apps/$4");
normalizations.put("(Starting .* using Java .* on ).*( with PID [\\d]+ \\().*( started by ).*( in ).*(\\))",
"$1myhost$2" + this.applicationJar.get() + "$3myuser$4/opt/apps/$5");
for (Entry<String, String> normalization : normalizations.entrySet()) {
Pattern pattern = Pattern.compile(normalization.getKey());
normalizedLines = normalize(normalizedLines, pattern, normalization.getValue());
@ -190,7 +196,7 @@ public class ApplicationRunner extends DefaultTask {
List<String> normalizedLines = new ArrayList<>();
for (String line : lines) {
Matcher matcher = pattern.matcher(line);
StringBuilder transformed = new StringBuilder();
StringBuffer transformed = new StringBuffer();
while (matcher.find()) {
matched = true;
matcher.appendReplacement(transformed, replacement);

@ -22,6 +22,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
@ -110,8 +111,13 @@ public class DocumentPluginGoals extends DefaultTask {
writer.printf("`%s:%s:%s`%n", plugin.getGroupId(), plugin.getArtifactId(), plugin.getVersion());
writer.println();
writer.println(mojo.getDescription());
List<Parameter> parameters = mojo.getParameters().stream().filter(Parameter::isEditable).toList();
List<Parameter> requiredParameters = parameters.stream().filter(Parameter::isRequired).toList();
List<Parameter> parameters = mojo.getParameters()
.stream()
.filter(Parameter::isEditable)
.collect(Collectors.toList());
List<Parameter> requiredParameters = parameters.stream()
.filter(Parameter::isRequired)
.collect(Collectors.toList());
String detailsSectionId = sectionId + ".parameter-details";
if (!requiredParameters.isEmpty()) {
writer.println();
@ -122,7 +128,7 @@ public class DocumentPluginGoals extends DefaultTask {
}
List<Parameter> optionalParameters = parameters.stream()
.filter((parameter) -> !parameter.isRequired())
.toList();
.collect(Collectors.toList());
if (!optionalParameters.isEmpty()) {
writer.println();
writer.println();

@ -86,8 +86,8 @@ public class MavenExec extends JavaExec {
return existing;
}
return project.getConfigurations().create("maven", (maven) -> {
maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-embedder:3.6.3"));
maven.getDependencies().add(project.getDependencies().create("org.apache.maven:maven-compat:3.6.3"));
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.slf4j:slf4j-simple:1.7.5"));
maven.getDependencies()
.add(project.getDependencies()

@ -38,6 +38,9 @@ import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import io.spring.javaformat.config.IndentationStyle;
import io.spring.javaformat.config.JavaBaseline;
import io.spring.javaformat.config.JavaFormatConfig;
import io.spring.javaformat.formatter.FileEdit;
import io.spring.javaformat.formatter.FileFormatter;
import org.gradle.api.DefaultTask;
@ -99,6 +102,20 @@ import org.springframework.util.Assert;
*/
public class MavenPluginPlugin implements Plugin<Project> {
private static final JavaFormatConfig FORMATTER_CONFIG = new JavaFormatConfig() {
@Override
public JavaBaseline getJavaBaseline() {
return JavaBaseline.V8;
}
@Override
public IndentationStyle getIndentationStyle() {
return IndentationStyle.TABS;
}
};
@Override
public void apply(Project project) {
project.getPlugins().apply(JavaLibraryPlugin.class);
@ -173,7 +190,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
private MavenExec createGenerateHelpMojoTask(Project project, File helpMojoDir) {
MavenExec task = project.getTasks().create("generateHelpMojo", MavenExec.class);
task.setProjectDir(helpMojoDir);
task.args("org.apache.maven.plugins:maven-plugin-plugin:3.6.1:helpmojo");
task.args("org.apache.maven.plugins:maven-plugin-plugin:3.6.0:helpmojo");
task.getOutputs().dir(new File(helpMojoDir, "target/generated-sources/plugin"));
return task;
}
@ -240,7 +257,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
private MavenExec createGeneratePluginDescriptorTask(Project project, File mavenDir) {
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.0:descriptor");
generatePluginDescriptor.getOutputs().dir(new File(mavenDir, "target/classes/META-INF/maven"));
generatePluginDescriptor.getInputs()
.dir(new File(mavenDir, "target/classes/org"))
@ -310,7 +327,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
@TaskAction
void syncAndFormat() {
FileFormatter formatter = new FileFormatter();
FileFormatter formatter = new FileFormatter(FORMATTER_CONFIG);
for (File output : this.generator.getOutputs().getFiles()) {
formatter.formatFiles(getProject().fileTree(output), StandardCharsets.UTF_8)
.forEach((edit) -> save(output, edit));
@ -322,7 +339,7 @@ public class MavenPluginPlugin implements Plugin<Project> {
Path outputLocation = this.outputDir.toPath().resolve(relativePath);
try {
Files.createDirectories(outputLocation.getParent());
Files.writeString(outputLocation, edit.getFormattedContent());
Files.write(outputLocation, edit.getFormattedContent().getBytes(StandardCharsets.UTF_8));
}
catch (Exception ex) {
throw new TaskExecutionException(this, ex);
@ -387,7 +404,9 @@ public class MavenPluginPlugin implements Plugin<Project> {
@TaskAction
public void createRepository() {
for (ResolvedArtifactResult result : this.runtimeClasspath.getIncoming().getArtifacts()) {
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier identifier) {
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier) {
ModuleComponentIdentifier identifier = (ModuleComponentIdentifier) result.getId()
.getComponentIdentifier();
String fileName = result.getFile()
.getName()
.replace(identifier.getVersion() + "-" + identifier.getVersion(), identifier.getVersion());
@ -463,8 +482,6 @@ public class MavenPluginPlugin implements Plugin<Project> {
effectiveBom.property("spring-framework.version", versions::setProperty);
effectiveBom.property("jakarta-servlet.version", versions::setProperty);
effectiveBom.property("kotlin.version", versions::setProperty);
effectiveBom.property("assertj.version", versions::setProperty);
effectiveBom.property("junit-jupiter.version", versions::setProperty);
return versions;
}

@ -139,7 +139,7 @@ class PluginXmlParser {
@Override
public Iterator<Node> iterator() {
return new Iterator<>() {
return new Iterator<Node>() {
private int index = 0;

@ -35,7 +35,7 @@ import org.gradle.api.tasks.TaskAction;
*/
public class PrepareMavenBinaries extends DefaultTask {
private final Set<String> versions = new LinkedHashSet<>();
private Set<String> versions = new LinkedHashSet<>();
private File outputDir;

@ -1,39 +0,0 @@
/*
* Copyright 2022-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.processors;
import com.diffplug.gradle.eclipse.apt.AptEclipsePlugin;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.plugins.ide.eclipse.model.EclipseModel;
/**
* A plugin for a project that uses one or more annotations processors.
*
* @author Andy Wilkinson
*/
public class ProcessedAnnotationsPlugin implements Plugin<Project> {
@Override
public void apply(Project project) {
project.getPlugins().apply(AptEclipsePlugin.class);
project.getExtensions()
.getByType(EclipseModel.class)
.synchronizationTasks("eclipseJdtApt", "eclipseJdt", "eclipseFactorypath");
}
}

@ -16,12 +16,11 @@
package org.springframework.boot.build.testing;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import org.gradle.api.DefaultTask;
import org.gradle.api.services.BuildService;
import org.gradle.api.services.BuildServiceParameters;
import org.gradle.api.tasks.testing.Test;
@ -37,12 +36,16 @@ import org.gradle.tooling.events.OperationCompletionListener;
public abstract class TestResultsOverview
implements BuildService<BuildServiceParameters.None>, OperationCompletionListener, AutoCloseable {
private final Map<Test, List<TestFailure>> testFailures = new TreeMap<>(Comparator.comparing(DefaultTask::getPath));
private final Map<Test, List<TestFailure>> testFailures = new TreeMap<>(
(one, two) -> one.getPath().compareTo(two.getPath()));
private final Object monitor = new Object();
void addFailures(Test test, List<TestDescriptor> failureDescriptors) {
List<TestFailure> testFailures = failureDescriptors.stream().map(TestFailure::new).sorted().toList();
List<TestFailure> testFailures = failureDescriptors.stream()
.map(TestFailure::new)
.sorted()
.collect(Collectors.toList());
synchronized (this.monitor) {
this.testFailures.put(test, testFailures);
}

@ -76,7 +76,7 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("sourceCompatibility = '17'");
out.println("sourceCompatibility = '1.8'");
out.println("description 'Test project for manifest customization'");
out.println("jar.archiveFileName = 'test.jar'");
}
@ -93,7 +93,7 @@ class ConventionsPluginTests {
.isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("1.8");
}
}
@ -106,7 +106,7 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("sourceCompatibility = '17'");
out.println("sourceCompatibility = '1.8'");
out.println("description 'Test'");
}
runGradle("assemble");
@ -122,7 +122,7 @@ class ConventionsPluginTests {
.isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("1.8");
}
}
@ -135,7 +135,7 @@ class ConventionsPluginTests {
out.println(" id 'org.springframework.boot.conventions'");
out.println("}");
out.println("version = '1.2.3'");
out.println("sourceCompatibility = '17'");
out.println("sourceCompatibility = '1.8'");
out.println("description 'Test'");
}
runGradle("assemble");
@ -151,7 +151,7 @@ class ConventionsPluginTests {
.isEqualTo(this.projectDir.getName().replace("-", "."));
assertThat(mainAttributes.getValue("Implementation-Version")).isEqualTo("1.2.3");
assertThat(mainAttributes.getValue("Built-By")).isEqualTo("Spring");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("17");
assertThat(mainAttributes.getValue("Build-Jdk-Spec")).isEqualTo("1.8");
}
}

@ -45,7 +45,7 @@ class ArchitectureCheckTests {
@Test
void whenPackagesAreTangledTaskFailsAndWritesAReport() throws Exception {
prepareTask("tangled", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThatExceptionOfType(GradleException.class).isThrownBy(() -> architectureCheck.checkArchitecture());
assertThat(failureReport(architectureCheck).length()).isGreaterThan(0);
});
}
@ -65,7 +65,7 @@ class ArchitectureCheckTests {
@Test
void whenBeanPostProcessorBeanMethodIsNotStaticTaskFailsAndWritesAReport() throws Exception {
prepareTask("bpp/nonstatic", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThatExceptionOfType(GradleException.class).isThrownBy(() -> architectureCheck.checkArchitecture());
assertThat(failureReport(architectureCheck).length()).isGreaterThan(0);
});
}
@ -73,7 +73,7 @@ class ArchitectureCheckTests {
@Test
void whenBeanPostProcessorBeanMethodIsStaticAndHasUnsafeParametersTaskFailsAndWritesAReport() throws Exception {
prepareTask("bpp/unsafeparameters", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThatExceptionOfType(GradleException.class).isThrownBy(() -> architectureCheck.checkArchitecture());
assertThat(failureReport(architectureCheck).length()).isGreaterThan(0);
});
}
@ -99,7 +99,7 @@ class ArchitectureCheckTests {
@Test
void whenBeanFactoryPostProcessorBeanMethodIsNotStaticTaskFailsAndWritesAReport() throws Exception {
prepareTask("bfpp/nonstatic", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThatExceptionOfType(GradleException.class).isThrownBy(() -> architectureCheck.checkArchitecture());
assertThat(failureReport(architectureCheck).length()).isGreaterThan(0);
});
}
@ -107,7 +107,7 @@ class ArchitectureCheckTests {
@Test
void whenBeanFactoryPostProcessorBeanMethodIsStaticAndHasParametersTaskFailsAndWritesAReport() throws Exception {
prepareTask("bfpp/parameters", (architectureCheck) -> {
assertThatExceptionOfType(GradleException.class).isThrownBy(architectureCheck::checkArchitecture);
assertThatExceptionOfType(GradleException.class).isThrownBy(() -> architectureCheck.checkArchitecture());
assertThat(failureReport(architectureCheck).length()).isGreaterThan(0);
});
}

@ -20,6 +20,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Properties;
@ -48,14 +49,14 @@ class UpgradeApplicatorTests {
void whenUpgradeIsAppliedToLibraryWithVersionThenBomIsUpdated() throws IOException {
File bom = new File(this.temp, "bom.gradle");
FileCopyUtils.copy(new File("src/test/resources/bom.gradle"), bom);
String originalContents = Files.readString(bom.toPath());
String originalContents = new String(Files.readAllBytes(bom.toPath()), StandardCharsets.UTF_8);
File gradleProperties = new File(this.temp, "gradle.properties");
FileCopyUtils.copy(new File("src/test/resources/gradle.properties"), gradleProperties);
new UpgradeApplicator(bom.toPath(), gradleProperties.toPath())
.apply(new Upgrade(new Library("ActiveMQ", null, new LibraryVersion(DependencyVersion.parse("5.15.11")),
null, null, false), DependencyVersion.parse("5.16")));
String bomContents = Files.readString(bom.toPath());
assertThat(bomContents).hasSize(originalContents.length() - 3);
String bomContents = new String(Files.readAllBytes(bom.toPath()), StandardCharsets.UTF_8);
assertThat(bomContents.length()).isEqualTo(originalContents.length() - 3);
}
@Test

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -39,8 +39,8 @@ class CompoundRowTests {
row.addProperty(new ConfigurationProperty("spring.test.third", "java.lang.String"));
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test]]<<my.spring.test,`+spring.test.first+` +" + NEWLINE
+ "`+spring.test.second+` +" + NEWLINE + "`+spring.test.third+` +" + NEWLINE + ">>" + NEWLINE
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test]]<<my.spring.test,`+spring.test.first+` +"
+ NEWLINE + "`+spring.test.second+` +" + NEWLINE + "`+spring.test.third+` +" + NEWLINE + ">>" + NEWLINE
+ "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
}

@ -38,7 +38,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+something+`" + NEWLINE);
}
@ -49,7 +49,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
}
@ -60,7 +60,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\|second+`" + NEWLINE);
}
@ -71,7 +71,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first\\\\second+`" + NEWLINE);
}
@ -82,7 +82,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description with a \\| pipe.+++" + NEWLINE + "|" + NEWLINE);
}
@ -93,8 +93,9 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop.*+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
assertThat(asciidoc.toString())
.isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop.*+`>>" + NEWLINE
+ "|+++This is a description.+++" + NEWLINE + "|" + NEWLINE);
}
@Test
@ -105,7 +106,7 @@ class SingleRowTests {
SingleRow row = new SingleRow(SNIPPET, property);
Asciidoc asciidoc = new Asciidoc();
row.write(asciidoc);
assertThat(asciidoc).hasToString("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
assertThat(asciidoc.toString()).isEqualTo("|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>"
+ NEWLINE + "|+++This is a description.+++" + NEWLINE + "|`+first," + NEWLINE + "second," + NEWLINE
+ "third+`" + NEWLINE);
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -41,16 +41,17 @@ class TableTests {
Asciidoc asciidoc = new Asciidoc();
table.write(asciidoc);
// @formatter:off
assertThat(asciidoc).hasToString("[cols=\"4,3,3\", options=\"header\"]" + NEWLINE +
"|===" + NEWLINE +
"|Name|Description|Default Value" + NEWLINE + NEWLINE +
"|[[my.spring.test.other]]<<my.spring.test.other,`+spring.test.other+`>>" + NEWLINE +
"|+++This is another description.+++" + NEWLINE +
"|`+other value+`" + NEWLINE + NEWLINE +
"|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>" + NEWLINE +
"|+++This is a description.+++" + NEWLINE +
"|`+something+`" + NEWLINE + NEWLINE +
"|===" + NEWLINE);
assertThat(asciidoc.toString()).isEqualTo(
"[cols=\"4,3,3\", options=\"header\"]" + NEWLINE +
"|===" + NEWLINE +
"|Name|Description|Default Value" + NEWLINE + NEWLINE +
"|[[my.spring.test.other]]<<my.spring.test.other,`+spring.test.other+`>>" + NEWLINE +
"|+++This is another description.+++" + NEWLINE +
"|`+other value+`" + NEWLINE + NEWLINE +
"|[[my.spring.test.prop]]<<my.spring.test.prop,`+spring.test.prop+`>>" + NEWLINE +
"|+++This is a description.+++" + NEWLINE +
"|`+something+`" + NEWLINE + NEWLINE +
"|===" + NEWLINE);
// @formatter:on
}

@ -18,6 +18,7 @@ package org.springframework.boot.build.mavenplugin;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.stream.Collectors;
import org.junit.jupiter.api.Test;
@ -43,8 +44,8 @@ class PluginXmlParserTests {
assertThat(plugin.getArtifactId()).isEqualTo("spring-boot-maven-plugin");
assertThat(plugin.getVersion()).isEqualTo("2.2.0.GRADLE-SNAPSHOT");
assertThat(plugin.getGoalPrefix()).isEqualTo("spring-boot");
assertThat(plugin.getMojos().stream().map(PluginXmlParser.Mojo::getGoal)).containsExactly("build-info", "help",
"repackage", "run", "start", "stop");
assertThat(plugin.getMojos().stream().map(PluginXmlParser.Mojo::getGoal).collect(Collectors.toList()))
.containsExactly("build-info", "help", "repackage", "run", "start", "stop");
}
@Test

@ -24,6 +24,7 @@ import java.io.PrintWriter;
import java.io.StringReader;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.gradle.testkit.runner.BuildResult;
import org.gradle.testkit.runner.GradleRunner;
@ -185,7 +186,7 @@ class TestFailuresPluginIntegrationTests {
private List<String> readLines(String output) {
try (BufferedReader reader = new BufferedReader(new StringReader(output))) {
return reader.lines().toList();
return reader.lines().collect(Collectors.toList());
}
catch (IOException ex) {
throw new RuntimeException(ex);

@ -11,7 +11,7 @@ The pipeline can be deployed using the following command:
[source]
----
$ fly -t spring-boot set-pipeline -p spring-boot-3.2.x -c ci/pipeline.yml -l ci/parameters.yml
$ fly -t spring-boot set-pipeline -p spring-boot-2.7.x -c ci/pipeline.yml -l ci/parameters.yml
----
NOTE: This assumes that you have credhub integration configured with the appropriate

@ -0,0 +1,10 @@
FROM ubuntu:jammy-20230916
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
ADD get-docker-url.sh /get-docker-url.sh
RUN ./setup.sh java11
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
ADD docker-lib.sh /docker-lib.sh

@ -0,0 +1,10 @@
FROM ubuntu:jammy-20230916
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
ADD get-docker-url.sh /get-docker-url.sh
RUN ./setup.sh java8 java17
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
ADD docker-lib.sh /docker-lib.sh

@ -3,12 +3,8 @@ FROM ubuntu:jammy-20230916
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
ADD get-docker-url.sh /get-docker-url.sh
ADD get-docker-compose-url.sh /get-docker-compose-url.sh
RUN ./setup.sh java17 java21
RUN ./setup.sh java8 java21
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
ADD docker-lib.sh /docker-lib.sh

@ -3,12 +3,8 @@ FROM ubuntu:jammy-20230916
ADD setup.sh /setup.sh
ADD get-jdk-url.sh /get-jdk-url.sh
ADD get-docker-url.sh /get-docker-url.sh
ADD get-docker-compose-url.sh /get-docker-compose-url.sh
RUN ./setup.sh java17
RUN ./setup.sh java8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
ENV JAVA_HOME /opt/openjdk
ENV PATH $JAVA_HOME/bin:$PATH
ADD docker-lib.sh /docker-lib.sh

@ -1,5 +0,0 @@
#!/bin/bash
set -e
version="2.17.0"
echo "https://github.com/docker/compose/releases/download/v$version/docker-compose-linux-x86_64"

@ -2,6 +2,12 @@
set -e
case "$1" in
java8)
echo "https://github.com/bell-sw/Liberica/releases/download/8u382+6/bellsoft-jdk8u382+6-linux-amd64.tar.gz"
;;
java11)
echo "https://github.com/bell-sw/Liberica/releases/download/11.0.20.1+1/bellsoft-jdk11.0.20.1+1-linux-amd64.tar.gz"
;;
java17)
echo "https://github.com/bell-sw/Liberica/releases/download/17.0.8.1+1/bellsoft-jdk17.0.8.1+1-linux-amd64.tar.gz"
;;

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -50,7 +50,7 @@ class ArtifactCollector {
Collection<DeployableArtifact> collectArtifacts(Path root) {
try (Stream<Path> artifacts = Files.walk(root)) {
return artifacts.filter(Files::isRegularFile).filter(this.excludeFilter)
.map((artifact) -> deployableArtifact(artifact, root)).toList();
.map((artifact) -> deployableArtifact(artifact, root)).collect(Collectors.toList());
}
catch (IOException ex) {
throw new RuntimeException("Could not read artifacts from '" + root + "'");

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -208,7 +208,7 @@ public class SonatypeService {
List<String> failureMessages = Stream.of(activities).flatMap((activity) -> activity.events.stream())
.filter((event) -> event.severity > 0).flatMap((event) -> event.properties.stream())
.filter((property) -> "failureMessage".equals(property.name))
.map((property) -> " " + property.value).toList();
.map((property) -> " " + property.value).collect(Collectors.toList());
if (failureMessages.isEmpty()) {
logger.error("Close failed for unknown reasons");
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,8 +16,6 @@
package io.spring.concourse.releasescripts.artifactory;
import java.util.Base64;
import io.spring.concourse.releasescripts.ReleaseInfo;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
@ -31,6 +29,7 @@ import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.test.web.client.MockRestServiceServer;
import org.springframework.test.web.client.response.DefaultResponseCreator;
import org.springframework.util.Base64Utils;
import org.springframework.web.client.HttpClientErrorException;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
@ -70,11 +69,8 @@ class ArtifactoryServiceTests {
.andExpect(method(HttpMethod.POST))
.andExpect(content().json(
"{\"status\": \"staged\", \"sourceRepo\": \"libs-staging-local\", \"targetRepo\": \"libs-milestone-local\"}"))
.andExpect(
header("Authorization",
"Basic " + Base64.getEncoder()
.encodeToString(String.format("%s:%s", this.properties.getUsername(),
this.properties.getPassword()).getBytes())))
.andExpect(header("Authorization", "Basic " + Base64Utils.encodeToString(String
.format("%s:%s", this.properties.getUsername(), this.properties.getPassword()).getBytes())))
.andExpect(header("Content-Type", MediaType.APPLICATION_JSON.toString())).andRespond(withSuccess());
this.service.promote("libs-milestone-local", getReleaseInfo());
this.server.verify();

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -21,6 +21,7 @@ import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.stream.Collectors;
@ -104,7 +105,7 @@ class SonatypeServiceTests {
.filter((artifact) -> !artifact.startsWith("build-info.json"))
.map((artifact) -> requestTo(
"/service/local/staging/deployByRepositoryId/example-6789/" + artifact.toString()))
.collect(Collectors.toSet());
.collect(Collectors.toCollection(HashSet::new));
AnyOfRequestMatcher uploadRequestsMatcher = anyOf(uploads);
assertThat(uploadRequestsMatcher.candidates).hasSize(150);
this.server.expect(ExpectedCount.times(150), uploadRequestsMatcher).andExpect(method(HttpMethod.PUT))
@ -132,7 +133,7 @@ class SonatypeServiceTests {
.andRespond(withSuccess());
this.service.publish(getReleaseInfo(), artifactsRoot);
this.server.verify();
assertThat(uploadRequestsMatcher.candidates).isEmpty();
assertThat(uploadRequestsMatcher.candidates).hasSize(0);
}
}
@ -156,7 +157,7 @@ class SonatypeServiceTests {
.filter((artifact) -> !"build-info.json".equals(artifact.toString()))
.map((artifact) -> requestTo(
"/service/local/staging/deployByRepositoryId/example-6789/" + artifact.toString()))
.collect(Collectors.toSet());
.collect(Collectors.toCollection(HashSet::new));
AnyOfRequestMatcher uploadRequestsMatcher = anyOf(uploads);
assertThat(uploadRequestsMatcher.candidates).hasSize(150);
this.server.expect(ExpectedCount.times(150), uploadRequestsMatcher).andExpect(method(HttpMethod.PUT))
@ -184,7 +185,7 @@ class SonatypeServiceTests {
.isThrownBy(() -> this.service.publish(getReleaseInfo(), artifactsRoot))
.withMessage("Close failed");
this.server.verify();
assertThat(uploadRequestsMatcher.candidates).isEmpty();
assertThat(uploadRequestsMatcher.candidates).hasSize(0);
}
}

@ -2,13 +2,12 @@
set -ex
###########################################################
# OS and UTILS
# UTILS
###########################################################
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install --no-install-recommends -y locales tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq
locale-gen en_US.utf8
apt-get install --no-install-recommends -y tzdata ca-certificates net-tools libxml2-utils git curl libudev1 libxml2-utils iptables iproute2 jq
ln -fs /usr/share/zoneinfo/UTC /etc/localtime
dpkg-reconfigure --frontend noninteractive tzdata
rm -rf /var/lib/apt/lists/*
@ -38,7 +37,6 @@ if [[ $# -eq 2 ]]; then
test -f /opt/openjdk-toolchain/bin/javac
fi
###########################################################
# DOCKER
###########################################################
@ -53,12 +51,3 @@ curl -L https://github.com/progrium/entrykit/releases/download/v${ENTRYKIT_VERSI
chmod +x entrykit && \
mv entrykit /bin/entrykit && \
entrykit --symlink
###########################################################
# DOCKER COMPOSE
###########################################################
mkdir -p /usr/local/lib/docker/cli-plugins
DOCKER_COMPOSE_URL=$( ./get-docker-compose-url.sh )
curl -L ${DOCKER_COMPOSE_URL} -o /usr/local/lib/docker/cli-plugins/docker-compose
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose

@ -3,8 +3,8 @@ github-repo-name: "spring-projects/spring-boot"
homebrew-tap-repo: "https://github.com/spring-io/homebrew-tap.git"
docker-hub-organization: "springci"
artifactory-server: "https://repo.spring.io"
branch: "main"
milestone: "3.2.x"
branch: "2.7.x"
milestone: "2.7.x"
build-name: "spring-boot"
concourse-url: "https://ci.spring.io"
task-timeout: 2h00m

@ -169,6 +169,18 @@ resources:
source:
<<: *ci-registry-image-resource-source
repository: ((docker-hub-organization))/spring-boot-ci
- name: ci-image-jdk11
type: registry-image
icon: docker
source:
<<: *ci-registry-image-resource-source
repository: ((docker-hub-organization))/spring-boot-ci-jdk11
- name: ci-image-jdk17
type: registry-image
icon: docker
source:
<<: *ci-registry-image-resource-source
repository: ((docker-hub-organization))/spring-boot-ci-jdk17
- name: ci-image-jdk21
type: registry-image
icon: docker
@ -179,8 +191,8 @@ resources:
type: registry-image
icon: docker
source:
repository: paketobuildpacks/builder-jammy-base
tag: latest
repository: paketobuildpacks/builder
tag: base
- name: artifactory-repo
type: artifactory-resource
icon: package-variant
@ -199,6 +211,22 @@ resources:
access_token: ((github-ci-status-token))
branch: ((branch))
context: build
- name: repo-status-jdk11-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk11-build
- name: repo-status-jdk17-build
type: github-status-resource
icon: eye-check-outline
source:
repository: ((github-repo-name))
access_token: ((github-ci-status-token))
branch: ((branch))
context: jdk17-build
- name: repo-status-jdk21-build
type: github-status-resource
icon: eye-check-outline
@ -242,6 +270,20 @@ jobs:
image: ci-image
vars:
ci-image-name: ci-image
- task: build-ci-image-jdk11
privileged: true
file: git-repo/ci/tasks/build-ci-image.yml
output_mapping:
image: ci-image-jdk11
vars:
ci-image-name: ci-image-jdk11
- task: build-ci-image-jdk17
privileged: true
file: git-repo/ci/tasks/build-ci-image.yml
output_mapping:
image: ci-image-jdk17
vars:
ci-image-name: ci-image-jdk17
- task: build-ci-image-jdk21
privileged: true
file: git-repo/ci/tasks/build-ci-image.yml
@ -253,6 +295,12 @@ jobs:
- put: ci-image
params:
image: ci-image/image.tar
- put: ci-image-jdk11
params:
image: ci-image-jdk11/image.tar
- put: ci-image-jdk17
params:
image: ci-image-jdk17/image.tar
- put: ci-image-jdk21
params:
image: ci-image-jdk21/image.tar
@ -263,6 +311,18 @@ jobs:
trigger: true
- get: ci-image
- in_parallel:
- task: detect-jdk8-update
image: ci-image
file: git-repo/ci/tasks/detect-jdk-updates.yml
params:
<<: *github-task-params
JDK_VERSION: java8
- task: detect-jdk11-update
image: ci-image
file: git-repo/ci/tasks/detect-jdk-updates.yml
params:
<<: *github-task-params
JDK_VERSION: java11
- task: detect-jdk17-update
image: ci-image
file: git-repo/ci/tasks/detect-jdk-updates.yml
@ -334,6 +394,63 @@ jobs:
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk11-build
serial: true
public: true
plan:
- get: ci-image-jdk11
- get: git-repo
trigger: true
- put: repo-status-jdk11-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
image: ci-image-jdk11
<<: *build-project-task-params
on_failure:
do:
- put: repo-status-jdk11-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk11-build
params: { state: "success", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk17-build
serial: true
public: true
plan:
- get: ci-image-jdk17
- get: git-repo
trigger: true
- put: repo-status-jdk17-build
params: { state: "pending", commit: "git-repo" }
- do:
- task: build-project
image: ci-image-jdk17
privileged: true
timeout: ((task-timeout))
file: git-repo/ci/tasks/build-project.yml
params:
BRANCH: ((branch))
TOOLCHAIN_JAVA_VERSION: 17
<<: *gradle-enterprise-task-params
<<: *docker-hub-task-params
on_failure:
do:
- put: repo-status-jdk17-build
params: { state: "failure", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-fail-params
- put: repo-status-jdk17-build
params: { state: "success", commit: "git-repo" }
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk21-build
serial: true
public: true
@ -636,6 +753,57 @@ jobs:
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk11-run-system-tests
serial: true
public: true
plan:
- get: ci-image-jdk11
- get: git-repo
- get: paketo-builder-base-image
trigger: true
- get: daily
trigger: true
- do:
- task: run-system-tests
image: ci-image-jdk11
<<: *run-system-tests-task-params
on_failure:
do:
- put: slack-alert
params:
<<: *slack-fail-params
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk17-run-system-tests
serial: true
public: true
plan:
- get: ci-image-jdk17
- get: git-repo
- get: paketo-builder-base-image
trigger: true
- get: daily
trigger: true
- do:
- task: run-system-tests
image: ci-image-jdk17
privileged: true
timeout: ((task-timeout))
file: git-repo/ci/tasks/run-system-tests.yml
params:
BRANCH: ((branch))
TOOLCHAIN_JAVA_VERSION: 17
<<: *gradle-enterprise-task-params
<<: *docker-hub-task-params
on_failure:
do:
- put: slack-alert
params:
<<: *slack-fail-params
- put: slack-alert
params:
<<: *slack-success-params
- name: jdk21-run-system-tests
serial: true
public: true
@ -667,11 +835,11 @@ jobs:
<<: *slack-success-params
groups:
- name: "builds"
jobs: ["build", "jdk21-build", "windows-build"]
jobs: ["build", "jdk11-build", "jdk17-build", "jdk21-build", "windows-build"]
- name: "releases"
jobs: ["stage-milestone", "stage-rc", "stage-release", "promote-milestone", "promote-rc", "promote-release", "create-github-release", "publish-gradle-plugin", "publish-to-sdkman", "update-homebrew-tap"]
- name: "system-tests"
jobs: ["run-system-tests", "jdk21-run-system-tests"]
jobs: ["run-system-tests", "jdk11-run-system-tests", "jdk17-run-system-tests", "jdk21-run-system-tests"]
- name: "ci-images"
jobs: ["build-ci-images", "detect-docker-updates", "detect-jdk-updates", "detect-ubuntu-image-updates"]

@ -1,4 +1,4 @@
SET "JAVA_HOME=C:\opt\jdk-17"
SET "JAVA_HOME=C:\opt\jdk-8"
SET PATH=%PATH%;C:\Program Files\Git\usr\bin
cd git-repo
.\gradlew -Dorg.gradle.internal.launcher.welcomeMessageEnabled=false --no-daemon --max-workers=4 build

@ -1,6 +1,9 @@
source /opt/concourse-java.sh
setup_symlinks
if [[ -d $PWD/embedmongo && ! -d $HOME/.embedmongo ]]; then
ln -s "$PWD/embedmongo" "$HOME/.embedmongo"
fi
cleanup_maven_repo "org.springframework.boot"

@ -8,9 +8,17 @@ report_error() {
trap 'report_error $? $LINENO' ERR
case "$JDK_VERSION" in
java8)
BASE_URL="https://api.bell-sw.com/v1/liberica/releases?version-feature=8"
ISSUE_TITLE="Upgrade Java 8 version in CI image and .sdkmanrc"
;;
java11)
BASE_URL="https://api.bell-sw.com/v1/liberica/releases?version-feature=11"
ISSUE_TITLE="Upgrade Java 11 version in CI image"
;;
java17)
BASE_URL="https://api.bell-sw.com/v1/liberica/releases?version-feature=17"
ISSUE_TITLE="Upgrade Java 17 version in CI image and .sdkmanrc"
ISSUE_TITLE="Upgrade Java 17 version in CI image"
;;
java21)
BASE_URL="https://api.bell-sw.com/v1/liberica/releases?version-feature=21"

@ -7,7 +7,7 @@ git clone homebrew-tap-repo updated-homebrew-tap-repo > /dev/null
if [[ $LATEST_GA = true ]]; then
pushd updated-homebrew-tap-repo > /dev/null
curl https://repo.maven.apache.org/maven2/org/springframework/boot/spring-boot-cli/${version}/spring-boot-cli-${version}-homebrew.rb --output spring-boot-cli-${version}-homebrew.rb
curl https://repo.spring.io/libs-release-local/org/springframework/boot/spring-boot-cli/${version}/spring-boot-cli-${version}-homebrew.rb --output spring-boot-cli-${version}-homebrew.rb
rm spring-boot.rb
mv spring-boot-cli-*.rb spring-boot.rb
git config user.name "Spring Builds" > /dev/null

@ -8,6 +8,7 @@ outputs:
caches:
- path: gradle
- path: maven
- path: embedmongo
params:
BRANCH:
CI: true

@ -11,8 +11,8 @@
xmlns:setup.workingsets="http://www.eclipse.org/oomph/setup/workingsets/1.0"
xmlns:workingsets="http://www.eclipse.org/oomph/workingsets/1.0"
xsi:schemaLocation="http://www.eclipse.org/oomph/setup/jdt/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/JDT.ecore http://www.eclipse.org/buildship/oomph/1.0 https://raw.githubusercontent.com/eclipse/buildship/master/org.eclipse.buildship.oomph/model/GradleImport-1.0.ecore http://www.eclipse.org/oomph/predicates/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/Predicates.ecore http://www.eclipse.org/oomph/setup/workingsets/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/SetupWorkingSets.ecore http://www.eclipse.org/oomph/workingsets/1.0 http://git.eclipse.org/c/oomph/org.eclipse.oomph.git/plain/setups/models/WorkingSets.ecore"
name="spring.boot.3.2.x"
label="Spring Boot 3.2.x">
name="spring.boot.2.7.x"
label="Spring Boot 2.7.x">
<setupTask
xsi:type="setup:VariableTask"
type="FOLDER"
@ -22,8 +22,8 @@
label="Checkout Location"/>
<setupTask
xsi:type="jdt:JRETask"
version="JavaSE-17"
location="${jre.location-17}">
version="JavaSE-1.8"
location="${jre.location-1.8}">
<description>
Define the JRE needed to compile and run the Java
projects of ${scope.project.label}
@ -107,14 +107,14 @@
</setupTask>
<setupTask
xsi:type="oomph:GradleImportTask"
javaHome="${jre.location-17}">
javaHome="${jre.location-1.8}">
<sourceLocator
rootFolder="${checkout.location}"
locateNestedProjects="true"/>
</setupTask>
<setupTask
xsi:type="oomph:GradleImportTask"
javaHome="${jre.location-17}">
javaHome="${jre.location-1.8}">
<sourceLocator
rootFolder="${checkout.location}/buildSrc"/>
</setupTask>
@ -136,7 +136,7 @@
name="spring-boot-tools">
<predicate
xsi:type="predicates:NamePredicate"
pattern="spring-boot-(tools|antlib|configuration-.*|loader|loader-classic|.*-tools|.*-layertools|.*-plugin|autoconfigure-processor|buildpack.*)"/>
pattern="spring-boot-(tools|antlib|configuration-.*|loader|.*-tools|.*-layertools|.*-plugin|autoconfigure-processor|buildpack.*)"/>
</workingSet>
<workingSet
name="spring-boot-starters">

@ -4,13 +4,13 @@ require 'net/http'
require 'yaml'
require 'logger'
$main_branch = "3.2.x"
$main_branch = "2.7.x"
$log = Logger.new(STDOUT)
$log.level = Logger::WARN
def get_fixed_issues()
$log.debug "Searching for forward merge"
$log.debug "Searching for for forward merge"
rev=`git rev-parse -q --verify MERGE_HEAD`.strip
$log.debug "Found #{rev} from git rev-parse"
return nil unless rev
@ -65,7 +65,7 @@ if message_type != "merge"
exit 0;
end
$log.debug "Searching for forward merge"
$log.debug "Searching for for forward merge"
fixed = get_fixed_issues()
rewritten_message = rewrite_message(message_file, fixed)
File.write(message_file, rewritten_message)

@ -1,18 +1,17 @@
version=3.2.0-SNAPSHOT
version=2.7.17-SNAPSHOT
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2g -Dfile.encoding=UTF-8
assertjVersion=3.24.2
commonsCodecVersion=1.16.0
assertjVersion=3.22.0
commonsCodecVersion=1.15
hamcrestVersion=2.2
jacksonVersion=2.15.2
junitJupiterVersion=5.10.0
kotlinVersion=1.9.10
jacksonVersion=2.13.5
junitJupiterVersion=5.8.2
kotlinVersion=1.6.21
mavenVersion=3.9.4
nativeBuildToolsVersion=0.9.27
springFrameworkVersion=6.1.0-SNAPSHOT
tomcatVersion=10.1.13
springFrameworkVersion=5.3.30
tomcatVersion=9.0.80
kotlin.stdlib.default.dependency=false

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.3-bin.zip
networkTimeout=10000
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

@ -5,7 +5,6 @@ pluginManagement {
if (version.endsWith('-SNAPSHOT')) {
maven { url "https://repo.spring.io/snapshot" }
}
}
resolutionStrategy {
eachPlugin {
@ -26,8 +25,6 @@ plugins {
rootProject.name="spring-boot-build"
enableFeaturePreview("STABLE_CONFIGURATION_CACHE")
settings.gradle.projectsLoaded {
gradleEnterprise {
buildScan {
@ -52,33 +49,28 @@ include "spring-boot-project:spring-boot-parent"
include "spring-boot-project:spring-boot-tools:spring-boot-antlib"
include "spring-boot-project:spring-boot-tools:spring-boot-autoconfigure-processor"
include "spring-boot-project:spring-boot-tools:spring-boot-buildpack-platform"
include "spring-boot-project:spring-boot-tools:spring-boot-cli"
include "spring-boot-project:spring-boot-tools:spring-boot-configuration-metadata"
include "spring-boot-project:spring-boot-tools:spring-boot-configuration-metadata-changelog-generator"
include "spring-boot-project:spring-boot-tools:spring-boot-configuration-processor"
include "spring-boot-project:spring-boot-tools:spring-boot-gradle-plugin"
include "spring-boot-project:spring-boot-tools:spring-boot-gradle-test-support"
include "spring-boot-project:spring-boot-tools:spring-boot-jarmode-layertools"
include "spring-boot-project:spring-boot-tools:spring-boot-loader"
include "spring-boot-project:spring-boot-tools:spring-boot-loader-classic"
include "spring-boot-project:spring-boot-tools:spring-boot-loader-tools"
include "spring-boot-project:spring-boot-tools:spring-boot-maven-plugin"
include "spring-boot-project:spring-boot-tools:spring-boot-properties-migrator"
include "spring-boot-project:spring-boot-tools:spring-boot-test-support"
include "spring-boot-project:spring-boot"
include "spring-boot-project:spring-boot-autoconfigure"
include "spring-boot-project:spring-boot-actuator"
include "spring-boot-project:spring-boot-actuator-autoconfigure"
include "spring-boot-project:spring-boot-docker-compose"
include "spring-boot-project:spring-boot-cli"
include "spring-boot-project:spring-boot-devtools"
include "spring-boot-project:spring-boot-docs"
include "spring-boot-project:spring-boot-properties-migrator"
include "spring-boot-project:spring-boot-test"
include "spring-boot-project:spring-boot-testcontainers"
include "spring-boot-project:spring-boot-test-autoconfigure"
include "spring-boot-tests:spring-boot-integration-tests:spring-boot-configuration-processor-tests"
include "spring-boot-tests:spring-boot-integration-tests:spring-boot-launch-script-tests"
include "spring-boot-tests:spring-boot-integration-tests:spring-boot-loader-tests"
include "spring-boot-tests:spring-boot-integration-tests:spring-boot-loader-classic-tests"
include "spring-boot-tests:spring-boot-integration-tests:spring-boot-server-tests"
include "spring-boot-system-tests:spring-boot-deployment-tests"
include "spring-boot-system-tests:spring-boot-image-tests"

@ -2,7 +2,6 @@ plugins {
id "java-library"
id "org.asciidoctor.jvm.convert"
id "org.springframework.boot.auto-configuration"
id "org.springframework.boot.configuration-properties"
id "org.springframework.boot.conventions"
id "org.springframework.boot.deployed"
id "org.springframework.boot.optional-dependencies"
@ -19,6 +18,7 @@ dependencies {
asciidoctorExtensions("io.spring.asciidoctor:spring-asciidoctor-extensions-section-ids")
api(project(":spring-boot-project:spring-boot-actuator"))
api(project(":spring-boot-project:spring-boot"))
api(project(":spring-boot-project:spring-boot-autoconfigure"))
@ -33,15 +33,11 @@ dependencies {
optional("com.github.ben-manes.caffeine:caffeine")
optional("com.hazelcast:hazelcast")
optional("com.hazelcast:hazelcast-spring")
optional("com.sun.mail:jakarta.mail")
optional("com.zaxxer:HikariCP")
optional("io.dropwizard.metrics:metrics-jmx")
optional("io.lettuce:lettuce-core")
optional("io.micrometer:micrometer-observation")
optional("io.micrometer:micrometer-jakarta9")
optional("io.micrometer:micrometer-tracing")
optional("io.micrometer:micrometer-tracing-bridge-brave")
optional("io.micrometer:micrometer-tracing-bridge-otel")
optional("io.micrometer:micrometer-tracing-reporter-wavefront")
optional("io.micrometer:micrometer-core")
optional("io.micrometer:micrometer-registry-appoptics")
optional("io.micrometer:micrometer-registry-atlas") {
exclude group: "javax.inject", module: "javax.inject"
@ -56,7 +52,6 @@ dependencies {
optional("io.micrometer:micrometer-registry-jmx")
optional("io.micrometer:micrometer-registry-kairos")
optional("io.micrometer:micrometer-registry-new-relic")
optional("io.micrometer:micrometer-registry-otlp")
optional("io.micrometer:micrometer-registry-prometheus")
optional("io.micrometer:micrometer-registry-stackdriver") {
exclude group: "commons-logging", module: "commons-logging"
@ -68,47 +63,59 @@ dependencies {
optional("io.micrometer:micrometer-registry-signalfx")
optional("io.micrometer:micrometer-registry-statsd")
optional("io.micrometer:micrometer-registry-wavefront")
optional("io.zipkin.reporter2:zipkin-reporter-brave")
optional("io.zipkin.reporter2:zipkin-sender-urlconnection")
optional("io.opentelemetry:opentelemetry-exporter-zipkin")
optional("io.opentelemetry:opentelemetry-exporter-otlp")
optional("io.projectreactor.netty:reactor-netty-http")
optional("io.r2dbc:r2dbc-pool")
optional("io.r2dbc:r2dbc-proxy")
optional("io.r2dbc:r2dbc-spi")
optional("jakarta.jms:jakarta.jms-api")
optional("jakarta.persistence:jakarta.persistence-api")
optional("jakarta.servlet:jakarta.servlet-api")
optional("javax.cache:cache-api")
optional("org.apache.activemq:activemq-client-jakarta")
optional("net.sf.ehcache:ehcache")
optional("org.apache.activemq:activemq-broker") {
exclude group: "org.apache.geronimo.specs", module: "geronimo-jms_1.1_spec"
exclude group: "org.apache.geronimo.specs", module: "geronimo-j2ee-management_1.1_spec"
}
optional("org.apache.commons:commons-dbcp2") {
exclude group: "commons-logging", module: "commons-logging"
}
optional("org.apache.kafka:kafka-clients")
optional("org.apache.kafka:kafka-streams")
optional("org.apache.logging.log4j:log4j-api")
optional("org.apache.solr:solr-solrj") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.apache.tomcat.embed:tomcat-embed-core")
optional("org.apache.tomcat.embed:tomcat-embed-el")
optional("org.apache.tomcat:tomcat-jdbc")
optional("org.aspectj:aspectjweaver")
optional("org.cache2k:cache2k-micrometer")
optional("org.cache2k:cache2k-spring")
optional("org.eclipse.angus:angus-mail")
optional("org.eclipse.jetty:jetty-server") {
exclude group: "org.eclipse.jetty.toolchain", module: "jetty-jakarta-servlet-api"
exclude group: "javax.servlet", module: "javax.servlet-api"
}
optional("org.elasticsearch:elasticsearch")
optional("org.elasticsearch.client:elasticsearch-rest-client") {
exclude group: "commons-logging", module: "commons-logging"
}
optional("org.flywaydb:flyway-core")
optional("org.glassfish.jersey.core:jersey-server")
optional("org.glassfish.jersey.containers:jersey-container-servlet-core")
optional("org.hibernate.orm:hibernate-core")
optional("org.hibernate.orm:hibernate-micrometer")
optional("org.hibernate:hibernate-core") {
exclude group: "javax.activation", module: "javax.activation-api"
exclude group: "javax.persistence", module: "javax.persistence-api"
exclude group: "javax.xml.bind", module: "jaxb-api"
exclude group: "org.jboss.spec.javax.transaction", module: "jboss-transaction-api_1.2_spec"
}
optional("org.hibernate:hibernate-micrometer") {
exclude group: "javax.activation", module: "javax.activation-api"
exclude group: "javax.persistence", module: "javax.persistence-api"
exclude group: "javax.xml.bind", module: "jaxb-api"
exclude group: "org.jboss.spec.javax.transaction", module: "jboss-transaction-api_1.2_spec"
}
optional("org.hibernate.validator:hibernate-validator")
optional("org.influxdb:influxdb-java")
optional("org.jolokia:jolokia-core")
optional("org.liquibase:liquibase-core") {
exclude group: "javax.activation", module: "javax.activation-api"
exclude group: "javax.xml.bind", module: "jaxb-api"
}
optional("org.mongodb:mongodb-driver-reactivestreams")
@ -121,11 +128,13 @@ dependencies {
optional("org.springframework:spring-webflux")
optional("org.springframework:spring-webmvc")
optional("org.springframework.amqp:spring-rabbit")
optional("org.springframework.batch:spring-batch-core")
optional("org.springframework.data:spring-data-cassandra") {
exclude group: "org.slf4j", module: "jcl-over-slf4j"
}
optional("org.springframework.data:spring-data-couchbase")
optional("org.springframework.data:spring-data-couchbase") {
exclude group: "com.querydsl", module: "querydsl-apt"
exclude group: "javax.annotation", module: "javax.annotation-api"
}
optional("org.springframework.data:spring-data-jpa")
optional("org.springframework.data:spring-data-ldap")
optional("org.springframework.data:spring-data-mongodb")
@ -143,27 +152,25 @@ dependencies {
testImplementation(project(":spring-boot-project:spring-boot-test"))
testImplementation(project(":spring-boot-project:spring-boot-tools:spring-boot-test-support"))
testImplementation("io.micrometer:micrometer-observation-test")
testImplementation("io.projectreactor:reactor-test")
testImplementation("io.r2dbc:r2dbc-h2")
testImplementation("com.squareup.okhttp3:mockwebserver")
testImplementation("com.jayway.jsonpath:json-path")
testImplementation("io.undertow:undertow-core")
testImplementation("io.undertow:undertow-servlet")
testImplementation("jakarta.xml.bind:jakarta.xml.bind-api")
testImplementation("org.apache.activemq:artemis-jakarta-client") {
exclude group: "commons-logging", module: "commons-logging"
}
testImplementation("org.apache.activemq:artemis-jakarta-server") {
exclude group: "commons-logging", module: "commons-logging"
testImplementation("io.undertow:undertow-servlet") {
exclude group: "org.jboss.spec.javax.annotation", module: "jboss-annotations-api_1.3_spec"
exclude group: "org.jboss.spec.javax.servlet", module: "jboss-servlet-api_4.0_spec"
}
testImplementation("jakarta.xml.bind:jakarta.xml.bind-api")
testImplementation("org.apache.logging.log4j:log4j-to-slf4j")
testImplementation("org.aspectj:aspectjrt")
testImplementation("org.assertj:assertj-core")
testImplementation("org.awaitility:awaitility")
testImplementation("org.cache2k:cache2k-api")
testImplementation("org.eclipse.jetty.ee10:jetty-ee10-webapp")
testImplementation("org.glassfish.jersey.ext:jersey-spring6")
testImplementation("org.eclipse.jetty:jetty-webapp") {
exclude group: "javax.servlet", module: "javax.servlet-api"
}
testImplementation("org.glassfish.jersey.ext:jersey-spring5")
testImplementation("org.glassfish.jersey.media:jersey-media-json-jackson")
testImplementation("org.hamcrest:hamcrest")
testImplementation("org.hsqldb:hsqldb")
@ -171,11 +178,12 @@ dependencies {
testImplementation("org.mockito:mockito-core")
testImplementation("org.mockito:mockito-junit-jupiter")
testImplementation("org.skyscreamer:jsonassert")
testImplementation("org.springframework:spring-core-test")
testImplementation("org.springframework:spring-orm")
testImplementation("org.springframework.data:spring-data-rest-webmvc")
testImplementation("org.springframework.integration:spring-integration-jmx")
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc") {
exclude group: "javax.servlet", module: "javax.servlet-api"
}
testImplementation("org.springframework.restdocs:spring-restdocs-webtestclient")
testImplementation("org.springframework.security:spring-security-test")
testImplementation("org.yaml:snakeyaml")
@ -183,17 +191,9 @@ dependencies {
testRuntimeOnly("jakarta.management.j2ee:jakarta.management.j2ee-api")
testRuntimeOnly("jakarta.transaction:jakarta.transaction-api")
testRuntimeOnly("org.cache2k:cache2k-core")
testRuntimeOnly("org.opensaml:opensaml-core:4.0.1")
testRuntimeOnly("org.opensaml:opensaml-saml-api:4.0.1")
testRuntimeOnly("org.opensaml:opensaml-saml-impl:4.0.1")
testRuntimeOnly("org.springframework:spring-aspects")
testRuntimeOnly("org.springframework.security:spring-security-oauth2-jose")
testRuntimeOnly("org.springframework.security:spring-security-oauth2-resource-server")
testRuntimeOnly("org.springframework.security:spring-security-saml2-service-provider") {
exclude group: "org.opensaml", module: "opensaml-core"
exclude group: "org.opensaml", module: "opensaml-saml-api"
exclude group: "org.opensaml", module: "opensaml-saml-impl"
}
testRuntimeOnly("org.springframework.security:spring-security-saml2-service-provider")
}
task dependencyVersions(type: org.springframework.boot.build.constraints.ExtractVersionConstraints) {
@ -229,7 +229,6 @@ artifacts {
}
tasks.named("test") {
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
filter {
excludeTestsMatching("org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation.*")
}
@ -239,7 +238,6 @@ def documentationTest = tasks.register("documentationTest", Test) {
filter {
includeTestsMatching("org.springframework.boot.actuate.autoconfigure.endpoint.web.documentation.*")
}
jvmArgs += "--add-opens=java.base/java.net=ALL-UNNAMED"
outputs.dir("${buildDir}/generated-snippets")
predictiveSelection {
enabled = false

@ -132,7 +132,3 @@ threaddump=threaddump
threaddump-retrieving-json=threaddump.retrieving-json
threaddump-retrieving-json-response-structure=threaddump.retrieving-json.response-structure
threaddump-retrieving-text=threaddump.retrieving-text
http-trace=httpexchanges
http-trace.retrieving=httpexchanges.retrieving
http-trace.retrieving.response-structure=httpexchanges.retrieving.response-structure

@ -23,7 +23,7 @@ The endpoint uses query parameters to limit the events that it returns.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/auditevents/filtered/query-parameters.adoc[]
include::{snippets}/auditevents/filtered/request-parameters.adoc[]

@ -46,7 +46,7 @@ Otherwise, the `cacheManager` must be specified.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/caches/named/query-parameters.adoc[]
include::{snippets}/caches/named/request-parameters.adoc[]
@ -85,4 +85,4 @@ Otherwise, the `cacheManager` must be specified.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/caches/evict-named/query-parameters.adoc[]
include::{snippets}/caches/evict-named/request-parameters.adoc[]

@ -1,25 +0,0 @@
[[httpexchanges]]
= HTTP Exchanges (`httpexchanges`)
The `httpexchanges` endpoint provides information about HTTP request-response exchanges.
[[httpexchanges.retrieving]]
== Retrieving the HTTP Exchanges
To retrieve the HTTP exchanges, make a `GET` request to `/actuator/httpexchanges`, as shown in the following curl-based example:
include::{snippets}/httpexchanges/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/httpexchanges/http-response.adoc[]
[[httpexchanges.retrieving.response-structure]]
=== Response Structure
The response contains details of the traced HTTP request-response exchanges.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/httpexchanges/response-fields.adoc[]

@ -0,0 +1,25 @@
[[http-trace]]
= HTTP Trace (`httptrace`)
The `httptrace` endpoint provides information about HTTP request-response exchanges.
[[http-trace.retrieving]]
== Retrieving the Traces
To retrieve the traces, make a `GET` request to `/actuator/httptrace`, as shown in the following curl-based example:
include::{snippets}/httptrace/curl-request.adoc[]
The resulting response is similar to the following:
include::{snippets}/httptrace/http-response.adoc[]
[[http-trace.retrieving.response-structure]]
=== Response Structure
The response contains details of the traced HTTP request-response exchanges.
The following table describes the structure of the response:
[cols="2,1,3"]
include::{snippets}/httptrace/response-fields.adoc[]

@ -45,7 +45,7 @@ The endpoint uses query parameters to <<metrics.drilling-down,drill down>> into
The following table shows the single supported query parameter:
[cols="2,4"]
include::{snippets}/metrics/metric-with-tags/query-parameters.adoc[]
include::{snippets}/metrics/metric-with-tags/request-parameters.adoc[]

@ -31,7 +31,7 @@ The endpoint uses query parameters to limit the samples that it returns.
The following table shows the supported query parameters:
[cols="2,4"]
include::{snippets}/prometheus/names/query-parameters.adoc[]
include::{snippets}/prometheus/names/request-parameters.adoc[]

@ -23,7 +23,7 @@ The endpoint uses query parameters to limit the sessions that it returns.
The following table shows the single required query parameter:
[cols="2,4"]
include::{snippets}/sessions/username/query-parameters.adoc[]
include::{snippets}/sessions/username/request-parameters.adoc[]

@ -72,7 +72,7 @@ include::endpoints/health.adoc[leveloffset=+1]
include::endpoints/heapdump.adoc[leveloffset=+1]
include::endpoints/httpexchanges.adoc[leveloffset=+1]
include::endpoints/httptrace.adoc[leveloffset=+1]
include::endpoints/info.adoc[leveloffset=+1]

@ -78,6 +78,18 @@ public abstract class OnEndpointElementCondition extends SpringBootCondition {
* @since 2.6.0
*/
protected ConditionOutcome getDefaultOutcome(ConditionContext context, AnnotationAttributes annotationAttributes) {
return getDefaultEndpointsOutcome(context);
}
/**
* Return the default outcome that should be used.
* @param context the condition context
* @return the default outcome
* @deprecated since 2.6.0 for removal in 3.0.0 in favor of
* {@link #getDefaultOutcome(ConditionContext, AnnotationAttributes)}
*/
@Deprecated
protected ConditionOutcome getDefaultEndpointsOutcome(ConditionContext context) {
boolean match = Boolean
.parseBoolean(context.getEnvironment().getProperty(this.prefix + "defaults.enabled", "true"));
return new ConditionOutcome(match, ConditionMessage.forCondition(this.annotationType)

@ -44,10 +44,6 @@ import org.springframework.context.annotation.Bean;
public class RabbitHealthContributorAutoConfiguration
extends CompositeHealthContributorConfiguration<RabbitHealthIndicator, RabbitTemplate> {
public RabbitHealthContributorAutoConfiguration() {
super(RabbitHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "rabbitHealthIndicator", "rabbitHealthContributor" })
public HealthContributor rabbitHealthContributor(Map<String, RabbitTemplate> rabbitTemplates) {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -43,10 +43,6 @@ class CassandraHealthContributorConfigurations {
static class CassandraDriverConfiguration
extends CompositeHealthContributorConfiguration<CassandraDriverHealthIndicator, CqlSession> {
CassandraDriverConfiguration() {
super(CassandraDriverHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" })
HealthContributor cassandraHealthContributor(Map<String, CqlSession> sessions) {
@ -60,10 +56,6 @@ class CassandraHealthContributorConfigurations {
static class CassandraReactiveDriverConfiguration extends
CompositeReactiveHealthContributorConfiguration<CassandraDriverReactiveHealthIndicator, CqlSession> {
CassandraReactiveDriverConfiguration() {
super(CassandraDriverReactiveHealthIndicator::new);
}
@Bean
@ConditionalOnMissingBean(name = { "cassandraHealthIndicator", "cassandraHealthContributor" })
ReactiveHealthContributor cassandraHealthContributor(Map<String, CqlSession> sessions) {

@ -19,10 +19,6 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry;
import java.util.Collection;
import java.util.List;
import org.springframework.aot.hint.MemberCategory;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer.CloudFoundryWebEndpointDiscovererRuntimeHints;
import org.springframework.boot.actuate.endpoint.EndpointFilter;
import org.springframework.boot.actuate.endpoint.invoke.OperationInvokerAdvisor;
import org.springframework.boot.actuate.endpoint.invoke.ParameterValueMapper;
@ -33,7 +29,6 @@ import org.springframework.boot.actuate.endpoint.web.annotation.EndpointWebExten
import org.springframework.boot.actuate.endpoint.web.annotation.WebEndpointDiscoverer;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.core.annotation.MergedAnnotations;
/**
@ -43,7 +38,6 @@ import org.springframework.core.annotation.MergedAnnotations;
* @author Madhura Bhave
* @since 2.0.0
*/
@ImportRuntimeHints(CloudFoundryWebEndpointDiscovererRuntimeHints.class)
public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
/**
@ -84,14 +78,4 @@ public class CloudFoundryWebEndpointDiscoverer extends WebEndpointDiscoverer {
return MergedAnnotations.from(extensionBeanType).isPresent(EndpointCloudFoundryExtension.class);
}
static class CloudFoundryWebEndpointDiscovererRuntimeHints implements RuntimeHintsRegistrar {
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
hints.reflection()
.registerType(CloudFoundryEndpointFilter.class, MemberCategory.INVOKE_DECLARED_CONSTRUCTORS);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -17,12 +17,12 @@
package org.springframework.boot.actuate.autoconfigure.cloudfoundry;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.util.Base64Utils;
import org.springframework.util.StringUtils;
/**
@ -60,7 +60,7 @@ public class Token {
private Map<String, Object> parseJson(String base64) {
try {
byte[] bytes = Base64.getUrlDecoder().decode(base64);
byte[] bytes = Base64Utils.decodeFromUrlSafeString(base64);
return JsonParserFactory.getJsonParser().parseMap(new String(bytes, StandardCharsets.UTF_8));
}
catch (RuntimeException ex) {
@ -73,7 +73,7 @@ public class Token {
}
public byte[] getSignature() {
return Base64.getUrlDecoder().decode(this.signature);
return Base64Utils.decodeFromUrlSafeString(this.signature);
}
public String getSignatureAlgorithm() {

@ -93,7 +93,8 @@ class CloudFoundrySecurityInterceptor {
}
private Mono<SecurityResponse> getErrorResponse(Throwable throwable) {
if (throwable instanceof CloudFoundryAuthorizationException cfException) {
if (throwable instanceof CloudFoundryAuthorizationException) {
CloudFoundryAuthorizationException cfException = (CloudFoundryAuthorizationException) throwable;
return Mono.just(new SecurityResponse(cfException.getStatusCode(),
"{\"security_error\":\"" + cfException.getMessage() + "\"}"));
}

@ -25,14 +25,8 @@ import java.util.stream.Collectors;
import org.reactivestreams.Publisher;
import reactor.core.publisher.Mono;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.CloudFoundryWebFluxEndpointHandlerMapping.CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -42,7 +36,6 @@ import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.server.reactive.ServerHttpRequest;
@ -58,7 +51,6 @@ import org.springframework.web.server.ServerWebExchange;
* @author Phillip Webb
* @author Brian Clozel
*/
@ImportRuntimeHints(CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints.class)
class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointHandlerMapping {
private final CloudFoundrySecurityInterceptor securityInterceptor;
@ -95,7 +87,6 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
class CloudFoundryLinksHandler implements LinksHandler {
@Override
@Reflective
public Publisher<ResponseEntity<Object>> links(ServerWebExchange exchange) {
ServerHttpRequest request = exchange.getRequest();
return CloudFoundryWebFluxEndpointHandlerMapping.this.securityInterceptor.preHandle(exchange, "")
@ -162,18 +153,4 @@ class CloudFoundryWebFluxEndpointHandlerMapping extends AbstractWebFluxEndpointH
}
static class CloudFoundryWebFluxEndpointHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

@ -22,6 +22,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectProvider;
@ -102,7 +103,7 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)
.toList();
.collect(Collectors.toList());
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
}
@ -174,14 +175,14 @@ public class ReactiveCloudFoundryActuatorAutoConfiguration {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebFilterChainProxy webFilterChainProxy) {
return postProcess(webFilterChainProxy);
if (bean instanceof WebFilterChainProxy) {
return postProcess((WebFilterChainProxy) bean, this.pathMappedEndpoints.get());
}
return bean;
}
private WebFilterChainProxy postProcess(WebFilterChainProxy existing) {
List<String> paths = getPaths(this.pathMappedEndpoints.get());
private WebFilterChainProxy postProcess(WebFilterChainProxy existing, PathMappedEndpoints pathMappedEndpoints) {
List<String> paths = getPaths(pathMappedEndpoints);
ServerWebExchangeMatcher cloudFoundryRequestMatcher = ServerWebExchangeMatchers
.pathMatchers(paths.toArray(new String[] {}));
WebFilter noOpFilter = (exchange, chain) -> chain.filter(exchange);

@ -31,7 +31,6 @@ import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryA
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.util.Assert;
import org.springframework.web.reactive.function.client.WebClient;
@ -46,16 +45,18 @@ import org.springframework.web.reactive.function.client.WebClientResponseExcepti
*/
class ReactiveCloudFoundrySecurityService {
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<>() {
private static final ParameterizedTypeReference<Map<String, Object>> STRING_OBJECT_MAP = new ParameterizedTypeReference<Map<String, Object>>() {
};
private final WebClient webClient;
private final String cloudControllerUrl;
private Mono<String> uaaUrl;
ReactiveCloudFoundrySecurityService(WebClient.Builder webClientBuilder, String cloudControllerUrl,
boolean skipSslValidation) {
Assert.notNull(webClientBuilder, "WebClient must not be null");
Assert.notNull(webClientBuilder, "Webclient must not be null");
Assert.notNull(cloudControllerUrl, "CloudControllerUrl must not be null");
if (skipSslValidation) {
webClientBuilder.clientConnector(buildTrustAllSslConnector());
@ -94,8 +95,8 @@ class ReactiveCloudFoundrySecurityService {
}
private Throwable mapError(Throwable throwable) {
if (throwable instanceof WebClientResponseException webClientResponseException) {
HttpStatusCode statusCode = webClientResponseException.getStatusCode();
if (throwable instanceof WebClientResponseException) {
HttpStatus statusCode = ((WebClientResponseException) throwable).getStatusCode();
if (statusCode.equals(HttpStatus.FORBIDDEN)) {
return new CloudFoundryAuthorizationException(Reason.ACCESS_DENIED, "Access denied");
}
@ -147,7 +148,7 @@ class ReactiveCloudFoundrySecurityService {
* @return the UAA url Mono
*/
Mono<String> getUaaUrl() {
return this.webClient.get()
this.uaaUrl = this.webClient.get()
.uri(this.cloudControllerUrl + "/info")
.retrieve()
.bodyToMono(Map.class)
@ -155,6 +156,7 @@ class ReactiveCloudFoundrySecurityService {
.cache()
.onErrorMap((ex) -> new CloudFoundryAuthorizationException(Reason.SERVICE_UNAVAILABLE,
"Unable to fetch token keys from UAA."));
return this.uaaUrl;
}
}

@ -23,7 +23,6 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@ -34,6 +33,7 @@ import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryAuthorizationException.Reason;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.Token;
import org.springframework.util.Base64Utils;
/**
* Validator used to ensure that a signed {@link Token} has not been tampered with.
@ -112,7 +112,7 @@ class ReactiveTokenValidator {
key = key.replace("-----BEGIN PUBLIC KEY-----\n", "");
key = key.replace("-----END PUBLIC KEY-----", "");
key = key.trim().replace("\n", "");
byte[] bytes = Base64.getDecoder().decode(key);
byte[] bytes = Base64Utils.decodeFromString(key);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(bytes);
return KeyFactory.getInstance("RSA").generatePublic(keySpec);
}

@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.CloudFoundryWebEndpointDiscoverer;
@ -107,7 +108,7 @@ public class CloudFoundryActuatorAutoConfiguration {
List<InfoContributor> contributors = infoContributors.orderedStream()
.map((infoContributor) -> (infoContributor instanceof GitInfoContributor)
? new GitInfoContributor(properties, InfoPropertiesInfoContributor.Mode.FULL) : infoContributor)
.toList();
.collect(Collectors.toList());
return new CloudFoundryInfoEndpointWebExtension(new InfoEndpoint(contributors));
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,7 +18,8 @@ package org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet;
import java.util.Locale;
import jakarta.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@ -77,7 +78,8 @@ class CloudFoundrySecurityInterceptor {
}
catch (Exception ex) {
logger.error(ex);
if (ex instanceof CloudFoundryAuthorizationException cfException) {
if (ex instanceof CloudFoundryAuthorizationException) {
CloudFoundryAuthorizationException cfException = (CloudFoundryAuthorizationException) ex;
return new SecurityResponse(cfException.getStatusCode(),
"{\"security_error\":\"" + cfException.getMessage() + "\"}");
}
@ -86,7 +88,7 @@ class CloudFoundrySecurityInterceptor {
return SecurityResponse.success();
}
private void check(HttpServletRequest request, EndpointId endpointId) {
private void check(HttpServletRequest request, EndpointId endpointId) throws Exception {
Token token = getToken(request);
this.tokenValidator.validate(token);
AccessLevel accessLevel = this.cloudFoundrySecurityService.getAccessLevel(token.toString(), this.applicationId);

@ -22,19 +22,14 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.stream.Collectors;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aot.hint.BindingReflectionHintsRegistrar;
import org.springframework.aot.hint.RuntimeHints;
import org.springframework.aot.hint.RuntimeHintsRegistrar;
import org.springframework.aot.hint.annotation.Reflective;
import org.springframework.aot.hint.annotation.ReflectiveRuntimeHintsRegistrar;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.AccessLevel;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.SecurityResponse;
import org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryWebEndpointServletHandlerMapping.CloudFoundryWebEndpointServletHandlerMappingRuntimeHints;
import org.springframework.boot.actuate.endpoint.EndpointId;
import org.springframework.boot.actuate.endpoint.ExposableEndpoint;
import org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver;
@ -44,7 +39,7 @@ import org.springframework.boot.actuate.endpoint.web.ExposableWebEndpoint;
import org.springframework.boot.actuate.endpoint.web.Link;
import org.springframework.boot.actuate.endpoint.web.WebOperation;
import org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping;
import org.springframework.context.annotation.ImportRuntimeHints;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ResponseBody;
@ -59,7 +54,6 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi
* @author Phillip Webb
* @author Brian Clozel
*/
@ImportRuntimeHints(CloudFoundryWebEndpointServletHandlerMappingRuntimeHints.class)
class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpointHandlerMapping {
private static final Log logger = LogFactory.getLog(CloudFoundryWebEndpointServletHandlerMapping.class);
@ -74,7 +68,8 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
Collection<ExposableWebEndpoint> endpoints, EndpointMediaTypes endpointMediaTypes,
CorsConfiguration corsConfiguration, CloudFoundrySecurityInterceptor securityInterceptor,
Collection<ExposableEndpoint<?>> allEndpoints) {
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true);
super(endpointMapping, endpoints, endpointMediaTypes, corsConfiguration, true,
WebMvcAutoConfiguration.pathPatternParser);
this.securityInterceptor = securityInterceptor;
this.linksResolver = new EndpointLinksResolver(allEndpoints);
this.allEndpoints = allEndpoints;
@ -99,7 +94,6 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
@Override
@ResponseBody
@Reflective
public Map<String, Map<String, Link>> links(HttpServletRequest request, HttpServletResponse response) {
SecurityResponse securityResponse = CloudFoundryWebEndpointServletHandlerMapping.this.securityInterceptor
.preHandle(request, null);
@ -165,18 +159,4 @@ class CloudFoundryWebEndpointServletHandlerMapping extends AbstractWebMvcEndpoin
}
static class CloudFoundryWebEndpointServletHandlerMappingRuntimeHints implements RuntimeHintsRegistrar {
private final ReflectiveRuntimeHintsRegistrar reflectiveRegistrar = new ReflectiveRuntimeHintsRegistrar();
private final BindingReflectionHintsRegistrar bindingRegistrar = new BindingReflectionHintsRegistrar();
@Override
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
this.reflectiveRegistrar.registerRuntimeHints(hints, CloudFoundryLinksHandler.class);
this.bindingRegistrar.registerReflectionHints(hints.reflection(), Link.class);
}
}
}

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

Loading…
Cancel
Save