diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java index b74a7cb9933..e5f065c4339 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/AutoConfigurationImportSelectorTests.java @@ -29,10 +29,8 @@ import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; -import org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration; -import org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration; -import org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration; import org.springframework.boot.context.annotation.ImportCandidates; +import org.springframework.boot.testsupport.classpath.resources.WithResource; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.type.AnnotationMetadata; @@ -48,6 +46,15 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException; * @author Stephane Nicoll * @author Madhura Bhave */ +@WithResource(name = "META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports", content = """ + com.example.one.FirstAutoConfiguration + com.example.two.SecondAutoConfiguration + com.example.three.ThirdAutoConfiguration + com.example.four.FourthAutoConfiguration + com.example.five.FifthAutoConfiguration + com.example.six.SixthAutoConfiguration + org.springframework.boot.autoconfigure.AutoConfigurationImportSelectorTests$SeventhAutoConfiguration + """) class AutoConfigurationImportSelectorTests { private final TestAutoConfigurationImportSelector importSelector = new TestAutoConfigurationImportSelector(); @@ -63,6 +70,7 @@ class AutoConfigurationImportSelectorTests { this.importSelector.setBeanFactory(this.beanFactory); this.importSelector.setEnvironment(this.environment); this.importSelector.setResourceLoader(new DefaultResourceLoader()); + this.importSelector.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); } @Test @@ -77,7 +85,7 @@ class AutoConfigurationImportSelectorTests { String[] imports = selectImports(EnableAutoConfigurationWithClassExclusions.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(FreeMarkerAutoConfiguration.class.getName()); + .contains(SeventhAutoConfiguration.class.getName()); } @Test @@ -85,7 +93,7 @@ class AutoConfigurationImportSelectorTests { String[] imports = selectImports(SpringBootApplicationWithClassExclusions.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(FreeMarkerAutoConfiguration.class.getName()); + .contains(SeventhAutoConfiguration.class.getName()); } @Test @@ -93,7 +101,7 @@ class AutoConfigurationImportSelectorTests { String[] imports = selectImports(EnableAutoConfigurationWithClassNameExclusions.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(MustacheAutoConfiguration.class.getName()); + .contains("com.example.one.FirstAutoConfiguration"); } @Test @@ -101,36 +109,36 @@ class AutoConfigurationImportSelectorTests { String[] imports = selectImports(SpringBootApplicationWithClassNameExclusions.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(MustacheAutoConfiguration.class.getName()); + .contains("com.example.three.ThirdAutoConfiguration"); } @Test void propertyExclusionsAreApplied() { - this.environment.setProperty("spring.autoconfigure.exclude", FreeMarkerAutoConfiguration.class.getName()); + this.environment.setProperty("spring.autoconfigure.exclude", "com.example.three.ThirdAutoConfiguration"); String[] imports = selectImports(BasicEnableAutoConfiguration.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 1); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(FreeMarkerAutoConfiguration.class.getName()); + .contains("com.example.three.ThirdAutoConfiguration"); } @Test void severalPropertyExclusionsAreApplied() { this.environment.setProperty("spring.autoconfigure.exclude", - FreeMarkerAutoConfiguration.class.getName() + "," + MustacheAutoConfiguration.class.getName()); + "com.example.two.SecondAutoConfiguration,com.example.four.FourthAutoConfiguration"); testSeveralPropertyExclusionsAreApplied(); } @Test void severalPropertyExclusionsAreAppliedWithExtraSpaces() { this.environment.setProperty("spring.autoconfigure.exclude", - FreeMarkerAutoConfiguration.class.getName() + " , " + MustacheAutoConfiguration.class.getName() + " "); + "com.example.two.SecondAutoConfiguration , com.example.four.FourthAutoConfiguration "); testSeveralPropertyExclusionsAreApplied(); } @Test void severalPropertyYamlExclusionsAreApplied() { - this.environment.setProperty("spring.autoconfigure.exclude[0]", FreeMarkerAutoConfiguration.class.getName()); - this.environment.setProperty("spring.autoconfigure.exclude[1]", MustacheAutoConfiguration.class.getName()); + this.environment.setProperty("spring.autoconfigure.exclude[0]", "com.example.two.SecondAutoConfiguration"); + this.environment.setProperty("spring.autoconfigure.exclude[1]", "com.example.four.FourthAutoConfiguration"); testSeveralPropertyExclusionsAreApplied(); } @@ -138,17 +146,17 @@ class AutoConfigurationImportSelectorTests { String[] imports = selectImports(BasicEnableAutoConfiguration.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 2); assertThat(this.importSelector.getLastEvent().getExclusions()) - .contains(FreeMarkerAutoConfiguration.class.getName(), MustacheAutoConfiguration.class.getName()); + .contains("com.example.two.SecondAutoConfiguration", "com.example.four.FourthAutoConfiguration"); } @Test void combinedExclusionsAreApplied() { - this.environment.setProperty("spring.autoconfigure.exclude", ThymeleafAutoConfiguration.class.getName()); + this.environment.setProperty("spring.autoconfigure.exclude", "com.example.one.FirstAutoConfiguration"); String[] imports = selectImports(EnableAutoConfigurationWithClassAndClassNameExclusions.class); assertThat(imports).hasSize(getAutoConfigurationClassNames().size() - 3); assertThat(this.importSelector.getLastEvent().getExclusions()).contains( - FreeMarkerAutoConfiguration.class.getName(), MustacheAutoConfiguration.class.getName(), - ThymeleafAutoConfiguration.class.getName()); + "com.example.one.FirstAutoConfiguration", "com.example.five.FifthAutoConfiguration", + SeventhAutoConfiguration.class.getName()); } @Test @@ -213,7 +221,8 @@ class AutoConfigurationImportSelectorTests { } private List getAutoConfigurationClassNames() { - return ImportCandidates.load(AutoConfiguration.class, getClass().getClassLoader()).getCandidates(); + return ImportCandidates.load(AutoConfiguration.class, Thread.currentThread().getContextClassLoader()) + .getCandidates(); } private final class TestAutoConfigurationImportSelector extends AutoConfigurationImportSelector { @@ -278,23 +287,23 @@ class AutoConfigurationImportSelectorTests { } - @EnableAutoConfiguration(exclude = FreeMarkerAutoConfiguration.class) + @EnableAutoConfiguration(exclude = SeventhAutoConfiguration.class) private final class EnableAutoConfigurationWithClassExclusions { } - @SpringBootApplication(exclude = FreeMarkerAutoConfiguration.class) + @SpringBootApplication(exclude = SeventhAutoConfiguration.class) private final class SpringBootApplicationWithClassExclusions { } - @EnableAutoConfiguration(excludeName = "org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration") + @EnableAutoConfiguration(excludeName = "com.example.one.FirstAutoConfiguration") private final class EnableAutoConfigurationWithClassNameExclusions { } - @EnableAutoConfiguration(exclude = MustacheAutoConfiguration.class, - excludeName = "org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration") + @EnableAutoConfiguration(exclude = SeventhAutoConfiguration.class, + excludeName = "com.example.five.FifthAutoConfiguration") private final class EnableAutoConfigurationWithClassAndClassNameExclusions { } @@ -315,9 +324,14 @@ class AutoConfigurationImportSelectorTests { } - @SpringBootApplication(excludeName = "org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration") + @SpringBootApplication(excludeName = "com.example.three.ThirdAutoConfiguration") private final class SpringBootApplicationWithClassNameExclusions { } + @AutoConfiguration + static class SeventhAutoConfiguration { + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java index 7a794fd3c84..d209c68793a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/ImportAutoConfigurationImportSelectorTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2023 the original author or authors. + * 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. @@ -79,7 +79,7 @@ class ImportAutoConfigurationImportSelectorTests { AnnotationMetadata annotationMetadata = getAnnotationMetadata(FromImportsFile.class); String[] imports = this.importSelector.selectImports(annotationMetadata); assertThat(imports).containsExactly( - "org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration", + "org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration", "org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration"); } @@ -89,8 +89,8 @@ class ImportAutoConfigurationImportSelectorTests { FromImportsFileIgnoresMissingOptionalClasses.class); String[] imports = this.importSelector.selectImports(annotationMetadata); assertThat(imports).containsExactly( - "org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration", - "org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration"); + "org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration", + "org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$AnotherImportedAutoConfiguration"); } @Test @@ -356,4 +356,14 @@ class ImportAutoConfigurationImportSelectorTests { } + @AutoConfiguration + static class ImportedAutoConfiguration { + + } + + @AutoConfiguration + static class AnotherImportedAutoConfiguration { + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportTests.java index fc1df6ace29..6ac69ca71b1 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionEvaluationReportTests.java @@ -16,9 +16,7 @@ package org.springframework.boot.autoconfigure.condition; -import java.util.ArrayList; import java.util.Iterator; -import java.util.List; import java.util.Map; import org.junit.jupiter.api.BeforeEach; @@ -31,6 +29,7 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome; import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes; +import org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration; import org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportMessage; import org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration; @@ -184,24 +183,6 @@ class ConditionEvaluationReportTests { assertThat(outcomes).hasSize(2); } - @Test - void duplicateOutcomes() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DuplicateConfig.class); - ConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory()); - String autoconfigKey = MultipartAutoConfiguration.class.getName(); - ConditionAndOutcomes outcomes = report.getConditionAndOutcomesBySource().get(autoconfigKey); - assertThat(outcomes).isNotNull(); - assertThat(outcomes).hasSize(2); - List messages = new ArrayList<>(); - for (ConditionAndOutcome outcome : outcomes) { - messages.add(outcome.getOutcome().getMessage()); - } - assertThat(messages).anyMatch((message) -> message.contains("@ConditionalOnClass found required classes " - + "'jakarta.servlet.Servlet', 'org.springframework.web.multipart." - + "support.StandardServletMultipartResolver', 'jakarta.servlet.MultipartConfigElement'")); - context.close(); - } - @Test void negativeOuterPositiveInnerBean() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @@ -220,13 +201,13 @@ class ConditionEvaluationReportTests { @Test void reportWhenSameShortNamePresentMoreThanOnceShouldUseFullyQualifiedName() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(WebMvcAutoConfiguration.class, + context.register(UniqueShortNameAutoConfiguration.class, org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration.class, org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration.class); context.refresh(); ConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory()); assertThat(report.getConditionAndOutcomesBySource()).containsKeys( - "org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration", + "org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration", "org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration", "org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration"); context.close(); @@ -235,17 +216,17 @@ class ConditionEvaluationReportTests { @Test void reportMessageWhenSameShortNamePresentMoreThanOnceShouldUseFullyQualifiedName() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.register(WebMvcAutoConfiguration.class, + context.register(UniqueShortNameAutoConfiguration.class, org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration.class, org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration.class); context.refresh(); ConditionEvaluationReport report = ConditionEvaluationReport.get(context.getBeanFactory()); String reportMessage = new ConditionEvaluationReportMessage(report).toString(); - assertThat(reportMessage).contains("WebMvcAutoConfiguration", + assertThat(reportMessage).contains("UniqueShortNameAutoConfiguration", "org.springframework.boot.autoconfigure.condition.config.first.SampleAutoConfiguration", "org.springframework.boot.autoconfigure.condition.config.second.SampleAutoConfiguration"); assertThat(reportMessage) - .doesNotContain("org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration"); + .doesNotContain("org.springframework.boot.autoconfigure.condition.config.UniqueShortNameAutoConfiguration"); context.close(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/UniqueShortNameAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/UniqueShortNameAutoConfiguration.java new file mode 100644 index 00000000000..818d070209c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/config/UniqueShortNameAutoConfiguration.java @@ -0,0 +1,32 @@ +/* + * 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.autoconfigure.condition.config; + +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; + +/** + * Uniquely named auto-configuration for {@link ConditionEvaluationReport} tests. + * + * @author Andy Wilkinson + */ +@AutoConfiguration +@ConditionalOnProperty("unique") +public class UniqueShortNameAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports index 42102d02a8f..951bbd8f242 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFile.imports @@ -1,2 +1,2 @@ -org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration +org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration \ No newline at end of file diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFileIgnoresMissingOptionalClasses.imports b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFileIgnoresMissingOptionalClasses.imports index b1639347423..c76445a839e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFileIgnoresMissingOptionalClasses.imports +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/resources/META-INF/spring/org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$FromImportsFileIgnoresMissingOptionalClasses.imports @@ -1,3 +1,3 @@ -optional:org.springframework.boot.autoconfigure.freemarker.FreeMarkerAutoConfiguration +optional:org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$ImportedAutoConfiguration optional:org.springframework.boot.autoconfigure.missing.MissingAutoConfiguration -org.springframework.boot.autoconfigure.thymeleaf.ThymeleafAutoConfiguration \ No newline at end of file +org.springframework.boot.autoconfigure.ImportAutoConfigurationImportSelectorTests$AnotherImportedAutoConfiguration \ No newline at end of file