Merge branch '3.4.x'
Build and Deploy Snapshot / Build and Deploy Snapshot (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:17], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:false version:21], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:${{ vars.UBUNTU_MEDIUM || 'ubuntu-latest' }} name:Linux]) (push) Has been cancelled Details
CI / ${{ matrix.os.name}} | Java ${{ matrix.java.version}} (map[toolchain:true version:24], map[id:windows-latest name:Windows]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:false version:17]) (push) Has been cancelled Details
Run System Tests / Java ${{ matrix.java.version}} (map[toolchain:true version:21]) (push) Has been cancelled Details
Build and Deploy Snapshot / Trigger Docs Build (push) Has been cancelled Details
Build and Deploy Snapshot / Verify (push) Has been cancelled Details

This commit is contained in:
Phillip Webb 2025-06-02 17:30:05 -07:00
commit a9b52c5892
13 changed files with 688 additions and 159 deletions

View File

@ -0,0 +1,135 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.springframework.asm.AnnotationVisitor;
import org.springframework.asm.ClassReader;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.SpringAsmInfo;
import org.springframework.asm.Type;
/**
* An {@code @AutoConfiguration} class.
*
* @param name name of the auto-configuration class
* @param before values of the {@code before} attribute
* @param beforeName values of the {@code beforeName} attribute
* @param after values of the {@code after} attribute
* @param afterName values of the {@code afterName} attribute
* @author Andy Wilkinson
*/
public record AutoConfigurationClass(String name, List<String> before, List<String> beforeName, List<String> after,
List<String> afterName) {
private AutoConfigurationClass(String name, Map<String, List<String>> attributes) {
this(name, attributes.getOrDefault("before", Collections.emptyList()),
attributes.getOrDefault("beforeName", Collections.emptyList()),
attributes.getOrDefault("after", Collections.emptyList()),
attributes.getOrDefault("afterName", Collections.emptyList()));
}
static AutoConfigurationClass of(File classFile) {
try (FileInputStream input = new FileInputStream(classFile)) {
ClassReader classReader = new ClassReader(input);
AutoConfigurationClassVisitor visitor = new AutoConfigurationClassVisitor();
classReader.accept(visitor, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES);
return visitor.autoConfigurationClass;
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
private static final class AutoConfigurationClassVisitor extends ClassVisitor {
private AutoConfigurationClass autoConfigurationClass;
private String name;
private AutoConfigurationClassVisitor() {
super(SpringAsmInfo.ASM_VERSION);
}
@Override
public void visit(int version, int access, String name, String signature, String superName,
String[] interfaces) {
this.name = Type.getObjectType(name).getClassName();
}
@Override
public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
String annotationClassName = Type.getType(descriptor).getClassName();
if ("org.springframework.boot.autoconfigure.AutoConfiguration".equals(annotationClassName)) {
return new AutoConfigurationAnnotationVisitor();
}
return null;
}
private final class AutoConfigurationAnnotationVisitor extends AnnotationVisitor {
private Map<String, List<String>> attributes = new HashMap<>();
private static final Set<String> INTERESTING_ATTRIBUTES = Set.of("before", "beforeName", "after",
"afterName");
private AutoConfigurationAnnotationVisitor() {
super(SpringAsmInfo.ASM_VERSION);
}
@Override
public void visitEnd() {
AutoConfigurationClassVisitor.this.autoConfigurationClass = new AutoConfigurationClass(
AutoConfigurationClassVisitor.this.name, this.attributes);
}
@Override
public AnnotationVisitor visitArray(String attributeName) {
if (INTERESTING_ATTRIBUTES.contains(attributeName)) {
return new AnnotationVisitor(SpringAsmInfo.ASM_VERSION) {
@Override
public void visit(String name, Object value) {
if (value instanceof Type type) {
value = type.getClassName();
}
AutoConfigurationAnnotationVisitor.this.attributes
.computeIfAbsent(attributeName, (n) -> new ArrayList<>())
.add(Objects.toString(value));
}
};
}
return null;
}
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.List;
import org.gradle.api.DefaultTask;
import org.gradle.api.Task;
import org.gradle.api.file.FileCollection;
import org.gradle.api.file.FileTree;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SkipWhenEmpty;
/**
* A {@link Task} that uses a project's auto-configuration imports.
*
* @author Andy Wilkinson
*/
public abstract class AutoConfigurationImportsTask extends DefaultTask {
static final String IMPORTS_FILE = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
private FileCollection sourceFiles = getProject().getObjects().fileCollection();
@InputFiles
@SkipWhenEmpty
@PathSensitive(PathSensitivity.RELATIVE)
public FileTree getSource() {
return this.sourceFiles.getAsFileTree().matching((filter) -> filter.include(IMPORTS_FILE));
}
public void setSource(Object source) {
this.sourceFiles = getProject().getObjects().fileCollection().from(source);
}
protected List<String> loadImports() {
File importsFile = getSource().getSingleFile();
try {
return Files.readAllLines(importsFile.toPath());
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

View File

@ -16,31 +16,25 @@
package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import com.tngtech.archunit.core.domain.JavaClass;
import com.tngtech.archunit.lang.ArchCondition;
import com.tngtech.archunit.lang.ArchRule;
import com.tngtech.archunit.lang.ConditionEvents;
import com.tngtech.archunit.lang.SimpleConditionEvent;
import com.tngtech.archunit.lang.syntax.ArchRuleDefinition;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.ConfigurationContainer;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.plugins.JavaBasePlugin;
import org.gradle.api.plugins.JavaPlugin;
import org.gradle.api.plugins.JavaPluginExtension;
import org.gradle.api.provider.Provider;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskContainer;
import org.gradle.api.tasks.TaskProvider;
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.optional.OptionalDependenciesPlugin;
/**
* {@link Plugin} for projects that define auto-configuration. When applied, the plugin
@ -52,12 +46,7 @@ import org.springframework.boot.build.architecture.ArchitecturePlugin;
* <li>Defines a task that produces metadata describing the auto-configuration. The
* metadata is made available as an artifact in the {@code autoConfigurationMetadata}
* configuration.
* <li>Reacts to the {@link ArchitecturePlugin} being applied and:
* <ul>
* <li>Adds a rule to the {@code checkArchitectureMain} task to verify that all
* {@code AutoConfiguration} classes are listed in the {@code AutoConfiguration.imports}
* file.
* </ul>
* <li>Add checks to ensure import files and annotations are correct</li>
* </ul>
*
* @author Andy Wilkinson
@ -70,102 +59,103 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
*/
public static final String AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME = "autoConfigurationMetadata";
private static final String AUTO_CONFIGURATION_IMPORTS_PATH = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
@Override
public void apply(Project project) {
project.getPlugins().apply(DeployedPlugin.class);
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> {
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-autoconfigure-processor")));
annotationProcessors.getDependencies()
.add(project.getDependencies()
.project(Collections.singletonMap("path",
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor")));
project.getTasks().register("autoConfigurationMetadata", AutoConfigurationMetadata.class, (task) -> {
SourceSet main = project.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
task.setSourceSet(main);
task.dependsOn(main.getClassesTaskName());
task.getOutputFile()
.set(project.getLayout().getBuildDirectory().file("auto-configuration-metadata.properties"));
project.getArtifacts()
.add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, task.getOutputFile(),
(artifact) -> artifact.builtBy(task));
project.getPlugins().withType(JavaPlugin.class, (javaPlugin) -> new Configurer(project).configure());
}
private static class Configurer {
private final Project project;
private SourceSet main;
Configurer(Project project) {
this.project = project;
this.main = project.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
}
void configure() {
addAnnotationProcessorsDependencies();
TaskContainer tasks = this.project.getTasks();
ConfigurationContainer configurations = this.project.getConfigurations();
tasks.register("autoConfigurationMetadata", AutoConfigurationMetadata.class,
this::configureAutoConfigurationMetadata);
TaskProvider<CheckAutoConfigurationImports> checkAutoConfigurationImports = tasks.register(
"checkAutoConfigurationImports", CheckAutoConfigurationImports.class,
this::configureCheckAutoConfigurationImports);
Configuration requiredClasspath = configurations.create("autoConfigurationRequiredClasspath")
.extendsFrom(configurations.getByName(this.main.getImplementationConfigurationName()),
configurations.getByName(this.main.getRuntimeOnlyConfigurationName()));
requiredClasspath.getDependencies()
.add(projectDependency(":spring-boot-project:spring-boot-autoconfigure"));
TaskProvider<CheckAutoConfigurationClasses> checkAutoConfigurationClasses = tasks.register(
"checkAutoConfigurationClasses", CheckAutoConfigurationClasses.class,
(task) -> configureCheckAutoConfigurationClasses(requiredClasspath, task));
this.project.getPlugins()
.withType(OptionalDependenciesPlugin.class,
(plugin) -> configureCheckAutoConfigurationClassesForOptionalDependencies(configurations,
checkAutoConfigurationClasses));
this.project.getTasks()
.getByName(JavaBasePlugin.CHECK_TASK_NAME)
.dependsOn(checkAutoConfigurationImports, checkAutoConfigurationClasses);
}
private void addAnnotationProcessorsDependencies() {
this.project.getConfigurations()
.getByName(JavaPlugin.ANNOTATION_PROCESSOR_CONFIGURATION_NAME)
.getDependencies()
.addAll(projectDependencies(
":spring-boot-project:spring-boot-tools:spring-boot-autoconfigure-processor",
":spring-boot-project:spring-boot-tools:spring-boot-configuration-processor"));
}
private void configureAutoConfigurationMetadata(AutoConfigurationMetadata task) {
task.setSourceSet(this.main);
task.dependsOn(this.main.getClassesTaskName());
task.getOutputFile()
.set(this.project.getLayout().getBuildDirectory().file("auto-configuration-metadata.properties"));
this.project.getArtifacts()
.add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME, task.getOutputFile(),
(artifact) -> artifact.builtBy(task));
}
private void configureCheckAutoConfigurationImports(CheckAutoConfigurationImports task) {
task.setSource(this.main.getResources());
task.setClasspath(this.main.getOutput().getClassesDirs());
task.setDescription(
"Checks the %s file of the main source set.".formatted(AutoConfigurationImportsTask.IMPORTS_FILE));
}
private void configureCheckAutoConfigurationClasses(Configuration requiredClasspath,
CheckAutoConfigurationClasses task) {
task.setSource(this.main.getResources());
task.setClasspath(this.main.getOutput().getClassesDirs());
task.setRequiredDependencies(requiredClasspath);
task.setDescription("Checks the auto-configuration classes of the main source set.");
}
private void configureCheckAutoConfigurationClassesForOptionalDependencies(
ConfigurationContainer configurations,
TaskProvider<CheckAutoConfigurationClasses> checkAutoConfigurationClasses) {
checkAutoConfigurationClasses.configure((check) -> {
Configuration optionalClasspath = configurations.create("autoConfigurationOptionalClassPath")
.extendsFrom(configurations.getByName(OptionalDependenciesPlugin.OPTIONAL_CONFIGURATION_NAME));
check.setOptionalDependencies(optionalClasspath);
});
project.getPlugins()
.withType(ArchitecturePlugin.class, (plugin) -> configureArchitecturePluginTasks(project));
});
}
}
private void configureArchitecturePluginTasks(Project project) {
project.getTasks().configureEach((task) -> {
if ("checkArchitectureMain".equals(task.getName()) && task instanceof ArchitectureCheck architectureCheck) {
configureCheckArchitectureMain(project, architectureCheck);
}
});
}
private Set<Dependency> projectDependencies(String... paths) {
return Arrays.stream(paths).map((path) -> projectDependency(path)).collect(Collectors.toSet());
}
private void configureCheckArchitectureMain(Project project, ArchitectureCheck architectureCheck) {
SourceSet main = project.getExtensions()
.getByType(JavaPluginExtension.class)
.getSourceSets()
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
File resourcesDirectory = main.getOutput().getResourcesDir();
architectureCheck.dependsOn(main.getProcessResourcesTaskName());
architectureCheck.getInputs()
.files(resourcesDirectory)
.optional()
.withPathSensitivity(PathSensitivity.RELATIVE);
architectureCheck.getRules()
.add(allClassesAnnotatedWithAutoConfigurationShouldBeListedInAutoConfigurationImports(
autoConfigurationImports(project, resourcesDirectory)));
}
private ArchRule allClassesAnnotatedWithAutoConfigurationShouldBeListedInAutoConfigurationImports(
Provider<AutoConfigurationImports> imports) {
return ArchRuleDefinition.classes()
.that()
.areAnnotatedWith("org.springframework.boot.autoconfigure.AutoConfiguration")
.should(beListedInAutoConfigurationImports(imports))
.allowEmptyShould(true);
}
private ArchCondition<JavaClass> beListedInAutoConfigurationImports(Provider<AutoConfigurationImports> imports) {
return new ArchCondition<>("be listed in " + AUTO_CONFIGURATION_IMPORTS_PATH) {
@Override
public void check(JavaClass item, ConditionEvents events) {
AutoConfigurationImports autoConfigurationImports = imports.get();
if (!autoConfigurationImports.imports.contains(item.getName())) {
events.add(SimpleConditionEvent.violated(item,
item.getName() + " was not listed in " + autoConfigurationImports.importsFile));
}
}
};
}
private Provider<AutoConfigurationImports> autoConfigurationImports(Project project, File resourcesDirectory) {
Path importsFile = new File(resourcesDirectory, AUTO_CONFIGURATION_IMPORTS_PATH).toPath();
return project.provider(() -> {
try {
return new AutoConfigurationImports(project.getProjectDir().toPath().relativize(importsFile),
Files.readAllLines(importsFile));
}
catch (IOException ex) {
throw new RuntimeException("Failed to read AutoConfiguration.imports", ex);
}
});
}
private record AutoConfigurationImports(Path importsFile, List<String> imports) {
private Dependency projectDependency(String path) {
return this.project.getDependencies().project(Collections.singletonMap("path", path));
}
}

View File

@ -0,0 +1,212 @@
/*
* Copyright 2012-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.stream.Stream;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* Task to check a project's {@code @AutoConfiguration} classes.
*
* @author Andy Wilkinson
*/
public abstract class CheckAutoConfigurationClasses extends AutoConfigurationImportsTask {
private FileCollection classpath = getProject().getObjects().fileCollection();
private FileCollection optionalDependencies = getProject().getObjects().fileCollection();
private FileCollection requiredDependencies = getProject().getObjects().fileCollection();
private SetProperty<String> optionalDependencyClassNames = getProject().getObjects().setProperty(String.class);
private SetProperty<String> requiredDependencyClassNames = getProject().getObjects().setProperty(String.class);
public CheckAutoConfigurationClasses() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
this.optionalDependencyClassNames.set(getProject().provider(() -> classNamesOf(this.optionalDependencies)));
this.requiredDependencyClassNames.set(getProject().provider(() -> classNamesOf(this.requiredDependencies)));
}
private static List<String> classNamesOf(FileCollection classpath) {
return classpath.getFiles().stream().flatMap((file) -> {
try (JarFile jarFile = new JarFile(file)) {
return Collections.list(jarFile.entries())
.stream()
.filter((entry) -> !entry.isDirectory())
.map(JarEntry::getName)
.filter((entryName) -> entryName.endsWith(".class"))
.map((entryName) -> entryName.substring(0, entryName.length() - ".class".length()))
.map((entryName) -> entryName.replace("/", "."));
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}).toList();
}
@Classpath
public FileCollection getClasspath() {
return this.classpath;
}
public void setClasspath(Object classpath) {
this.classpath = getProject().getObjects().fileCollection().from(classpath);
}
@Classpath
public FileCollection getOptionalDependencies() {
return this.optionalDependencies;
}
public void setOptionalDependencies(Object classpath) {
this.optionalDependencies = getProject().getObjects().fileCollection().from(classpath);
}
@Classpath
public FileCollection getRequiredDependencies() {
return this.requiredDependencies;
}
public void setRequiredDependencies(Object classpath) {
this.requiredDependencies = getProject().getObjects().fileCollection().from(classpath);
}
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@TaskAction
void execute() {
Map<String, List<String>> problems = new TreeMap<>();
Set<String> optionalOnlyClassNames = new HashSet<>(this.optionalDependencyClassNames.get());
Set<String> requiredClassNames = this.requiredDependencyClassNames.get();
optionalOnlyClassNames.removeAll(requiredClassNames);
classFiles().forEach((classFile) -> {
AutoConfigurationClass autoConfigurationClass = AutoConfigurationClass.of(classFile);
if (autoConfigurationClass != null) {
check(autoConfigurationClass, optionalOnlyClassNames, requiredClassNames, problems);
}
});
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
writeReport(problems, outputFile);
if (!problems.isEmpty()) {
throw new VerificationException(
"Auto-configuration class check failed. See '%s' for details".formatted(outputFile));
}
}
private List<File> classFiles() {
List<File> classFiles = new ArrayList<>();
for (File root : this.classpath.getFiles()) {
try (Stream<Path> files = Files.walk(root.toPath())) {
files.forEach((file) -> {
if (Files.isRegularFile(file) && file.getFileName().toString().endsWith(".class")) {
classFiles.add(file.toFile());
}
});
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
return classFiles;
}
private void check(AutoConfigurationClass autoConfigurationClass, Set<String> optionalOnlyClassNames,
Set<String> requiredClassNames, Map<String, List<String>> problems) {
if (!autoConfigurationClass.name().endsWith("AutoConfiguration")) {
problems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())
.add("Name of a class annotated with @AutoConfiguration should end with AutoConfiguration");
}
autoConfigurationClass.before().forEach((before) -> {
if (optionalOnlyClassNames.contains(before)) {
problems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())
.add("before '%s' is from an optional dependency and should be declared in beforeName"
.formatted(before));
}
});
autoConfigurationClass.beforeName().forEach((beforeName) -> {
if (!optionalOnlyClassNames.contains(beforeName)) {
String problem = requiredClassNames.contains(beforeName)
? "beforeName '%s' is from a required dependency and should be declared in before"
.formatted(beforeName)
: "beforeName '%s' not found".formatted(beforeName);
problems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>()).add(problem);
}
});
autoConfigurationClass.after().forEach((after) -> {
if (optionalOnlyClassNames.contains(after)) {
problems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>())
.add("after '%s' is from an optional dependency and should be declared in afterName"
.formatted(after));
}
});
autoConfigurationClass.afterName().forEach((afterName) -> {
if (!optionalOnlyClassNames.contains(afterName)) {
String problem = requiredClassNames.contains(afterName)
? "afterName '%s' is from a required dependency and should be declared in after"
.formatted(afterName)
: "afterName '%s' not found".formatted(afterName);
problems.computeIfAbsent(autoConfigurationClass.name(), (name) -> new ArrayList<>()).add(problem);
}
});
}
private void writeReport(Map<String, List<String>> problems, File outputFile) {
outputFile.getParentFile().mkdirs();
StringBuilder report = new StringBuilder();
if (!problems.isEmpty()) {
report.append("Found auto-configuration class problems:%n".formatted());
problems.forEach((className, classProblems) -> {
report.append(" - %s:%n".formatted(className));
classProblems.forEach((problem) -> report.append(" - %s%n".formatted(problem)));
});
}
try {
Files.writeString(outputFile.toPath(), report.toString(), StandardOpenOption.CREATE,
StandardOpenOption.TRUNCATE_EXISTING);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.build.autoconfigure;
import java.io.File;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.Classpath;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.VerificationException;
import org.gradle.language.base.plugins.LifecycleBasePlugin;
/**
* Task to check the contents of a project's
* {@code META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports}
* file.
*
* @author Andy Wilkinson
*/
public abstract class CheckAutoConfigurationImports extends AutoConfigurationImportsTask {
private FileCollection classpath = getProject().getObjects().fileCollection();
public CheckAutoConfigurationImports() {
getOutputDirectory().convention(getProject().getLayout().getBuildDirectory().dir(getName()));
setGroup(LifecycleBasePlugin.VERIFICATION_GROUP);
}
@Classpath
public FileCollection getClasspath() {
return this.classpath;
}
public void setClasspath(Object classpath) {
this.classpath = getProject().getObjects().fileCollection().from(classpath);
}
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@TaskAction
void execute() {
File importsFile = getSource().getSingleFile();
check(importsFile);
}
private void check(File importsFile) {
List<String> imports = loadImports();
List<String> problems = new ArrayList<>();
for (String imported : imports) {
File classFile = find(imported);
if (classFile == null) {
problems.add("'%s' was not found".formatted(imported));
}
else if (!correctlyAnnotated(classFile)) {
problems.add("'%s' is not annotated with @AutoConfiguration".formatted(imported));
}
}
List<String> sortedValues = new ArrayList<>(imports);
Collections.sort(sortedValues);
if (!sortedValues.equals(imports)) {
File sortedOutputFile = getOutputDirectory().file("sorted-" + importsFile.getName()).get().getAsFile();
writeString(sortedOutputFile,
sortedValues.stream().collect(Collectors.joining(System.lineSeparator())) + System.lineSeparator());
problems.add("Entries should be sorted alphabetically (expect content written to "
+ sortedOutputFile.getAbsolutePath() + ")");
}
File outputFile = getOutputDirectory().file("failure-report.txt").get().getAsFile();
writeReport(importsFile, problems, outputFile);
if (!problems.isEmpty()) {
throw new VerificationException("%s check failed. See '%s' for details"
.formatted(AutoConfigurationImportsTask.IMPORTS_FILE, outputFile));
}
}
private File find(String className) {
for (File root : this.classpath.getFiles()) {
String classFilePath = className.replace(".", "/") + ".class";
File classFile = new File(root, classFilePath);
if (classFile.isFile()) {
return classFile;
}
}
return null;
}
private boolean correctlyAnnotated(File classFile) {
return AutoConfigurationClass.of(classFile) != null;
}
private void writeReport(File importsFile, List<String> problems, File outputFile) {
outputFile.getParentFile().mkdirs();
StringBuilder report = new StringBuilder();
if (!problems.isEmpty()) {
report.append("Found problems in '%s':%n".formatted(importsFile));
problems.forEach((problem) -> report.append(" - %s%n".formatted(problem)));
}
writeString(outputFile, report.toString());
}
private void writeString(File file, String content) {
try {
Files.writeString(file.toPath(), content);
}
catch (IOException ex) {
throw new UncheckedIOException(ex);
}
}
}

View File

@ -80,14 +80,12 @@ public abstract class DocumentAutoConfigurationClasses extends DefaultTask {
writer.println("[cols=\"4,1\"]");
writer.println("|===");
writer.println("| Configuration Class | Links");
for (AutoConfigurationClass autoConfigurationClass : autoConfigurationClasses.classes) {
writer.println();
writer.printf("| {code-spring-boot}/spring-boot-project/%s/src/main/java/%s.java[`%s`]%n",
autoConfigurationClasses.module, autoConfigurationClass.path, autoConfigurationClass.name);
writer.printf("| xref:api:java/%s.html[javadoc]%n", autoConfigurationClass.path);
}
writer.println("|===");
}
}

View File

@ -21,13 +21,12 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.actuate.endpoint.jackson.EndpointObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBooleanProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
/**
@ -36,8 +35,7 @@ import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
* @author Phillip Webb
* @since 3.0.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(JacksonAutoConfiguration.class)
@AutoConfiguration(after = JacksonAutoConfiguration.class)
public class JacksonEndpointAutoConfiguration {
@Bean

View File

@ -30,12 +30,11 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.SimpleAutowireCandidateResolver;
import org.springframework.boot.actuate.autoconfigure.metrics.MetricsAutoConfiguration;
import org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetricsExportAutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;
/**
@ -46,8 +45,7 @@ import org.springframework.util.StringUtils;
* @author Stephane Nicoll
* @since 2.1.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter({ MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
@AutoConfiguration(after = { MetricsAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
SimpleMetricsExportAutoConfiguration.class })
@ConditionalOnClass({ EntityManagerFactory.class, SessionFactory.class, HibernateMetrics.class, MeterRegistry.class })
@ConditionalOnBean({ EntityManagerFactory.class, MeterRegistry.class })

View File

@ -7,14 +7,18 @@ org.springframework.boot.actuate.autoconfigure.beans.BeansEndpointAutoConfigurat
org.springframework.boot.actuate.autoconfigure.cache.CachesEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.cassandra.CassandraHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.cassandra.CassandraReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.cloudfoundry.reactive.ReactiveCloudFoundryActuatorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.cloudfoundry.servlet.CloudFoundryActuatorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.condition.ConditionsReportEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.context.ShutdownEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.couchbase.CouchbaseReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.elasticsearch.ElasticsearchReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.mongo.MongoHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.mongo.MongoReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.redis.RedisHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.redis.RedisReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.elasticsearch.ElasticsearchRestHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.EndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.endpoint.jackson.JacksonEndpointAutoConfiguration
@ -70,8 +74,6 @@ org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleMetri
org.springframework.boot.actuate.autoconfigure.metrics.export.stackdriver.StackdriverMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.export.statsd.StatsdMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.export.wavefront.WavefrontMetricsExportAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.batch.BatchObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.graphql.GraphQlObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.integration.IntegrationMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.jdbc.DataSourcePoolMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.jersey.JerseyServerMetricsAutoConfiguration
@ -81,30 +83,28 @@ org.springframework.boot.actuate.autoconfigure.metrics.r2dbc.ConnectionPoolMetri
org.springframework.boot.actuate.autoconfigure.metrics.redis.LettuceMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.startup.StartupTimeMetricsListenerAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.task.TaskExecutorMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.web.jetty.JettyMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.metrics.web.tomcat.TomcatMetricsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.mongo.MongoHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.mongo.MongoReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.ObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.batch.BatchObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.graphql.GraphQlObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.client.HttpClientObservationsAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.reactive.WebFluxObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.observation.web.servlet.WebMvcObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.opentelemetry.OpenTelemetryAutoConfiguration
org.springframework.boot.actuate.autoconfigure.quartz.QuartzEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.r2dbc.ConnectionFactoryHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.r2dbc.R2dbcObservationAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.redis.RedisHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.data.redis.RedisReactiveHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.sbom.SbomEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksObservabilityAutoConfiguration
org.springframework.boot.actuate.autoconfigure.security.reactive.ReactiveManagementWebSecurityAutoConfiguration
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
org.springframework.boot.actuate.autoconfigure.session.SessionsEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.startup.StartupEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.ssl.SslHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.ssl.SslObservabilityAutoConfiguration
org.springframework.boot.actuate.autoconfigure.startup.StartupEndpointAutoConfiguration
org.springframework.boot.actuate.autoconfigure.system.DiskSpaceHealthContributorAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.BraveAutoConfiguration
org.springframework.boot.actuate.autoconfigure.tracing.MicrometerTracingAutoConfiguration

View File

@ -47,7 +47,6 @@ class ObservationRegistryConfigurerIntegrationTests {
CalledCustomizers calledCustomizers = context.getBean(CalledCustomizers.class);
Customizer1 customizer1 = context.getBean(Customizer1.class);
Customizer2 customizer2 = context.getBean(Customizer2.class);
assertThat(calledCustomizers.getCustomizers()).containsExactly(customizer1, customizer2);
});
}

View File

@ -56,7 +56,7 @@ public class HttpExchangesFilter extends OncePerRequestFilter implements Ordered
private final Set<Include> includes;
/**
* Create a new instance.
* Create a new {@link HttpExchangesFilter} instance.
* @param repository the repository used to record events
* @param includes the include options
*/

View File

@ -18,10 +18,10 @@ package org.springframework.boot.autoconfigure.reactor;
import reactor.core.publisher.Hooks;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Reactor.
@ -29,7 +29,7 @@ import org.springframework.context.annotation.Configuration;
* @author Brian Clozel
* @since 3.2.0
*/
@Configuration(proxyBeanMethods = false)
@AutoConfiguration
@ConditionalOnClass(Hooks.class)
@EnableConfigurationProperties(ReactorProperties.class)
public class ReactorAutoConfiguration {

View File

@ -1,6 +1,7 @@
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration
@ -45,10 +46,10 @@ org.springframework.boot.autoconfigure.elasticsearch.ReactiveElasticsearchClient
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
org.springframework.boot.autoconfigure.graphql.GraphQlAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlReactiveQueryByExampleAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlReactiveQuerydslAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlQueryByExampleAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlQuerydslAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlReactiveQueryByExampleAutoConfiguration
org.springframework.boot.autoconfigure.graphql.data.GraphQlReactiveQuerydslAutoConfiguration
org.springframework.boot.autoconfigure.graphql.reactive.GraphQlWebFluxAutoConfiguration
org.springframework.boot.autoconfigure.graphql.rsocket.GraphQlRSocketAutoConfiguration
org.springframework.boot.autoconfigure.graphql.rsocket.RSocketGraphQlClientAutoConfiguration
@ -69,23 +70,22 @@ org.springframework.boot.autoconfigure.info.ProjectInfoAutoConfiguration
org.springframework.boot.autoconfigure.integration.IntegrationAutoConfiguration
org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JdbcClientAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration
org.springframework.boot.autoconfigure.jersey.JerseyAutoConfiguration
org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
org.springframework.boot.autoconfigure.jms.JndiConnectionFactoryAutoConfiguration
org.springframework.boot.autoconfigure.jms.activemq.ActiveMQAutoConfiguration
org.springframework.boot.autoconfigure.jms.artemis.ArtemisAutoConfiguration
org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration
org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration
org.springframework.boot.autoconfigure.jsonb.JsonbAutoConfiguration
org.springframework.boot.autoconfigure.kafka.KafkaAutoConfiguration
org.springframework.boot.autoconfigure.availability.ApplicationAvailabilityAutoConfiguration
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
org.springframework.boot.autoconfigure.ldap.LdapAutoConfiguration
org.springframework.boot.autoconfigure.ldap.embedded.EmbeddedLdapAutoConfiguration
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration
org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration
org.springframework.boot.autoconfigure.mail.MailSenderValidatorAutoConfiguration
@ -106,23 +106,23 @@ org.springframework.boot.autoconfigure.rsocket.RSocketMessagingAutoConfiguration
org.springframework.boot.autoconfigure.rsocket.RSocketRequesterAutoConfiguration
org.springframework.boot.autoconfigure.rsocket.RSocketServerAutoConfiguration
org.springframework.boot.autoconfigure.rsocket.RSocketStrategiesAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientWebSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerJwtAutoConfiguration
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration
org.springframework.boot.autoconfigure.security.rsocket.RSocketSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.OAuth2ClientAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientWebSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.client.reactive.ReactiveOAuth2ClientWebSecurityAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.resource.servlet.OAuth2ResourceServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.resource.reactive.ReactiveOAuth2ResourceServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerAutoConfiguration
org.springframework.boot.autoconfigure.security.oauth2.server.servlet.OAuth2AuthorizationServerJwtAutoConfiguration
org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration
org.springframework.boot.autoconfigure.ssl.SslAutoConfiguration
org.springframework.boot.autoconfigure.task.TaskExecutionAutoConfiguration
@ -144,13 +144,13 @@ org.springframework.boot.autoconfigure.web.reactive.error.ErrorWebFluxAutoConfig
org.springframework.boot.autoconfigure.web.reactive.function.client.ClientHttpConnectorAutoConfiguration
org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration
org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration
org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfiguration
org.springframework.boot.autoconfigure.webservices.client.WebServiceTemplateAutoConfiguration
org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration