Generate the AutoConfiguration.imports file from annotations
This commit adds the `AutoConfigurationImportsAnnotationProcessor` to the `spring-boot-autoconfigure-processor` annotation processor module. When added to a project build, the annotation processor will generate the `org.springframework.boot.autoconfigure.AutoConfiguration.imports` file automatically from `@AutoConfiguration`-annotated classes. It also applies the annotation processor to the Spring Boot build. Closes gh-31228
This commit is contained in:
@@ -23,15 +23,13 @@ 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;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.gradle.api.DefaultTask;
|
||||
import org.gradle.api.Task;
|
||||
@@ -43,16 +41,18 @@ 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 {
|
||||
|
||||
private static final String IMPORTS_FILE_PATH = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports";
|
||||
|
||||
private static final String COMMENT_START = "#";
|
||||
|
||||
private SourceSet sourceSet;
|
||||
@@ -60,13 +60,7 @@ 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"))
|
||||
getInputs().file((Callable<File>) this::findAutoConfigurationImportsFile)
|
||||
.withPathSensitivity(PathSensitivity.RELATIVE)
|
||||
.withPropertyName("org.springframework.boot.autoconfigure.AutoConfiguration");
|
||||
|
||||
@@ -99,9 +93,7 @@ public class AutoConfigurationMetadata extends DefaultTask {
|
||||
|
||||
private Properties readAutoConfiguration() throws IOException {
|
||||
Properties autoConfiguration = CollectionFactory.createSortedProperties(true);
|
||||
Set<String> classNames = new LinkedHashSet<>();
|
||||
classNames.addAll(readSpringFactories());
|
||||
classNames.addAll(readAutoConfigurationsFile());
|
||||
List<String> classNames = readAutoConfigurationsFile();
|
||||
Set<String> publicClassNames = new LinkedHashSet<>();
|
||||
for (String className : classNames) {
|
||||
File classFile = findClassFile(className);
|
||||
@@ -120,61 +112,41 @@ 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.
|
||||
* @return auto-configurations
|
||||
*/
|
||||
private List<String> readAutoConfigurationsFile() throws IOException {
|
||||
File file = new File(this.sourceSet.getOutput().getResourcesDir(),
|
||||
"META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports");
|
||||
if (!file.exists()) {
|
||||
File file = findAutoConfigurationImportsFile();
|
||||
if (file == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
// 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;
|
||||
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
|
||||
return reader.lines().map(this::stripComment).filter((line) -> !line.isEmpty())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
private String stripComment(String line) {
|
||||
int commentStart = line.indexOf(COMMENT_START);
|
||||
if (commentStart == -1) {
|
||||
return line;
|
||||
return line.trim();
|
||||
}
|
||||
return line.substring(0, commentStart);
|
||||
return line.substring(0, commentStart).trim();
|
||||
}
|
||||
|
||||
private File findAutoConfigurationImportsFile() {
|
||||
return findFileInClassesDirs(IMPORTS_FILE_PATH);
|
||||
}
|
||||
|
||||
private File findClassFile(String className) {
|
||||
String classFileName = className.replace(".", "/") + ".class";
|
||||
return findFileInClassesDirs(className.replace(".", "/") + ".class");
|
||||
}
|
||||
|
||||
private File findFileInClassesDirs(String fileName) {
|
||||
for (File classesDir : this.sourceSet.getOutput().getClassesDirs()) {
|
||||
File classFile = new File(classesDir, classFileName);
|
||||
File classFile = new File(classesDir, fileName);
|
||||
if (classFile.isFile()) {
|
||||
return classFile;
|
||||
}
|
||||
@@ -182,12 +154,4 @@ 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.springframework.boot.build.autoconfigure;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
@@ -43,6 +42,7 @@ import org.springframework.boot.build.context.properties.ConfigurationProperties
|
||||
* </ul>
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
public class AutoConfigurationPlugin implements Plugin<Project> {
|
||||
|
||||
@@ -62,9 +62,6 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
|
||||
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().create("autoConfigurationMetadata", AutoConfigurationMetadata.class, (task) -> {
|
||||
SourceSet main = project.getExtensions().getByType(JavaPluginExtension.class).getSourceSets()
|
||||
.getByName(SourceSet.MAIN_SOURCE_SET_NAME);
|
||||
@@ -72,7 +69,7 @@ public class AutoConfigurationPlugin implements Plugin<Project> {
|
||||
task.dependsOn(main.getClassesTaskName());
|
||||
task.setOutputFile(new File(project.getBuildDir(), "auto-configuration-metadata.properties"));
|
||||
project.getArtifacts().add(AutoConfigurationPlugin.AUTO_CONFIGURATION_METADATA_CONFIGURATION_NAME,
|
||||
project.provider((Callable<File>) task::getOutputFile), (artifact) -> artifact.builtBy(task));
|
||||
project.provider(task::getOutputFile), (artifact) -> artifact.builtBy(task));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user