Merge branch '3.1.x'

Closes gh-36661
This commit is contained in:
Andy Wilkinson
2023-08-01 18:14:03 +01:00
29 changed files with 153 additions and 11 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -61,7 +61,9 @@ public @interface ImportAutoConfiguration {
/**
* The auto-configuration classes that should be imported. When empty, the classes are
* specified using a file in {@code META-INF/spring} where the file name is the
* fully-qualified name of the annotated class, suffixed with '.imports'.
* fully-qualified name of the annotated class, suffixed with {@code .imports}. An
* entry in the file may be prefixed with {@code optional:} to indicate that the
* imported class should be ignored if it is not on the classpath.
* @return the classes to import
*/
@AliasFor("value")

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2012-2022 the original author or authors.
* Copyright 2012-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,6 +25,7 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import org.springframework.boot.context.annotation.DeterminableImports;
@@ -32,6 +33,7 @@ import org.springframework.boot.context.annotation.ImportCandidates;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
@@ -49,6 +51,8 @@ import org.springframework.util.ObjectUtils;
*/
class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelector implements DeterminableImports {
private static final String OPTIONAL_PREFIX = "optional:";
private static final Set<String> ANNOTATION_NAMES;
static {
@@ -92,13 +96,27 @@ class ImportAutoConfigurationImportSelector extends AutoConfigurationImportSelec
if (classes.length > 0) {
return Arrays.asList(classes);
}
return loadFactoryNames(source);
Collection<String> factoryNames = loadFactoryNames(source);
return factoryNames.stream().map((name) -> {
if (name.startsWith(OPTIONAL_PREFIX)) {
name = name.substring(OPTIONAL_PREFIX.length());
if (!present(name)) {
return null;
}
}
return name;
}).filter(Objects::nonNull).toList();
}
protected Collection<String> loadFactoryNames(Class<?> source) {
return ImportCandidates.load(source, getBeanClassLoader()).getCandidates();
}
private boolean present(String className) {
String resourcePath = ClassUtils.convertClassNameToResourcePath(className) + ".class";
return new ClassPathResource(resourcePath).exists();
}
@Override
protected Set<String> getExclusions(AnnotationMetadata metadata, AnnotationAttributes attributes) {
Set<String> exclusions = new LinkedHashSet<>();

View File

@@ -74,6 +74,25 @@ class ImportAutoConfigurationImportSelectorTests {
assertThat(imports).containsExactly(FreeMarkerAutoConfiguration.class.getName());
}
@Test
void importsAreSelectedFromImportsFile() throws Exception {
AnnotationMetadata annotationMetadata = getAnnotationMetadata(FromImportsFile.class);
String[] imports = this.importSelector.selectImports(annotationMetadata);
assertThat(imports).containsExactly(
"org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration",
"org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration");
}
@Test
void importsSelectedFromImportsFileIgnoreMissingOptionalClasses() throws Exception {
AnnotationMetadata annotationMetadata = getAnnotationMetadata(
FromImportsFileIgnoresMissingOptionalClasses.class);
String[] imports = this.importSelector.selectImports(annotationMetadata);
assertThat(imports).containsExactly(
"org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration",
"org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration");
}
@Test
void propertyExclusionsAreApplied() throws IOException {
this.environment.setProperty("spring.autoconfigure.exclude", FreeMarkerAutoConfiguration.class.getName());
@@ -312,6 +331,18 @@ class ImportAutoConfigurationImportSelectorTests {
}
@Retention(RetentionPolicy.RUNTIME)
@ImportAutoConfiguration
@interface FromImportsFile {
}
@Retention(RetentionPolicy.RUNTIME)
@ImportAutoConfiguration
@interface FromImportsFileIgnoresMissingOptionalClasses {
}
static class TestImportAutoConfigurationImportSelector extends ImportAutoConfigurationImportSelector {
@Override

View File

@@ -0,0 +1,2 @@
org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration

View File

@@ -0,0 +1,3 @@
optional:org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration
optional:org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration
org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration