Merge branch '4.0.x'

This commit is contained in:
Andy Wilkinson
2026-01-15 10:52:15 +00:00
2 changed files with 52 additions and 6 deletions
@@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
@@ -31,6 +32,7 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
@@ -347,6 +349,25 @@ class ConditionalOnBeanTests {
"customGenericExampleBean", "parameterizedContainerGenericExampleBean")));
}
@Test
void whenTypeDoesNotExistItIsStillDescribedInConditionOutcomeMessage() {
this.contextRunner.withUserConfiguration(OnBeanForTypeThatDoesNotExist.class).run((context) -> {
Map<String, ConditionAndOutcomes> conditionAndOutcomesBySource = ConditionEvaluationReport
.get(context.getBeanFactory())
.getConditionAndOutcomesBySource();
assertThat(conditionAndOutcomesBySource).hasEntrySatisfying(OnBeanForTypeThatDoesNotExist.class.getName(),
(conditionAndOutcomes) -> {
assertThat(conditionAndOutcomes).hasSize(1)
.first()
.extracting(ConditionAndOutcome::getOutcome)
.satisfies((outcome) -> {
assertThat(outcome.isMatch()).isFalse();
assertThat(outcome.getMessage()).contains("com.example.DoesNotExist");
});
});
});
}
private Consumer<ConfigurableApplicationContext> beansAndContainersNamed(Class<?> type, String... names) {
return (context) -> {
String[] beans = context.getBeanNamesForType(type);
@@ -833,4 +854,15 @@ class ConditionalOnBeanTests {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(type = "com.example.DoesNotExist")
static class OnBeanForTypeThatDoesNotExist {
@Bean
String bean() {
return "bean";
}
}
}
@@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.function.Consumer;
import org.junit.jupiter.api.Test;
@@ -31,6 +32,8 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport.ConditionAndOutcomes;
import org.springframework.boot.autoconfigure.condition.scan.ScanBean;
import org.springframework.boot.autoconfigure.condition.scan.ScannedFactoryBeanConfiguration;
import org.springframework.boot.autoconfigure.condition.scan.ScannedFactoryBeanWithBeanMethodArgumentsConfiguration;
@@ -506,11 +509,22 @@ class ConditionalOnMissingBeanTests {
}
@Test
void yep() {
this.contextRunner.withUserConfiguration(OnMissingBeanForTypeThatDoesNotExist.class)
.withInitializer(ConditionEvaluationReportLoggingListener.forLogLevel(LogLevel.INFO))
.run((context) -> {
});
void whenTypeDoesNotExistItIsStillDescribedInConditionOutcomeMessage() {
this.contextRunner.withUserConfiguration(OnMissingBeanForTypeThatDoesNotExist.class).run((context) -> {
Map<String, ConditionAndOutcomes> conditionAndOutcomesBySource = ConditionEvaluationReport
.get(context.getBeanFactory())
.getConditionAndOutcomesBySource();
assertThat(conditionAndOutcomesBySource)
.hasEntrySatisfying(OnMissingBeanForTypeThatDoesNotExist.class.getName(), (conditionAndOutcomes) -> {
assertThat(conditionAndOutcomes).hasSize(1)
.first()
.extracting(ConditionAndOutcome::getOutcome)
.satisfies((outcome) -> {
assertThat(outcome.isMatch()).isTrue();
assertThat(outcome.getMessage()).contains("com.example.DoesNotExist");
});
});
});
}
private Consumer<ConfigurableApplicationContext> beansAndContainersNamed(Class<?> type, String... names) {
@@ -1147,10 +1161,10 @@ class ConditionalOnMissingBeanTests {
}
@Configuration(proxyBeanMethods = false)
@ConditionalOnMissingBean(type = "com.example.DoesNotExist")
static class OnMissingBeanForTypeThatDoesNotExist {
@Bean
@ConditionalOnMissingBean(type = "com.example.DoesNotExist")
String bean() {
return "bean";
}