From 90f375ea3e2f5c9436f1bf6838a37bbf6e983d1c Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 2 Oct 2024 15:19:05 -0700 Subject: [PATCH] Dont deduce type for OnBean conditions when annotations are specified Update `OnBeanCondition` to consider the annotations attribute as well as the types and names when determining if the bean type can be deduced. Fixes gh-42484 --- .../condition/OnBeanCondition.java | 4 +- .../ConditionalOnMissingBeanTests.java | 44 +++++++++++++++++++ 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java index dc73aaf572..9cceb27c7a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/OnBeanCondition.java @@ -546,7 +546,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat this.strategy = annotation.getValue("search", SearchStrategy.class).orElse(null); Set types = extractTypes(attributes); BeanTypeDeductionException deductionException = null; - if (types.isEmpty() && this.names.isEmpty()) { + if (types.isEmpty() && this.names.isEmpty() && this.annotations.isEmpty()) { try { types = deducedBeanType(context, metadata); } @@ -602,7 +602,7 @@ class OnBeanCondition extends FilteringSpringBootCondition implements Configurat } protected void validate(BeanTypeDeductionException ex) { - if (!hasAtLeastOneElement(this.types, this.names, this.annotations)) { + if (!hasAtLeastOneElement(getTypes(), getNames(), getAnnotations())) { String message = getAnnotationName() + " did not specify a bean using type, name or annotation"; if (ex == null) { throw new IllegalStateException(message); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java index 830f2c17fc..a51172a0d9 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/condition/ConditionalOnMissingBeanTests.java @@ -137,6 +137,14 @@ class ConditionalOnMissingBeanTests { }); } + @Test // gh-42484 + void testAnnotationOnMissingBeanConditionOnMethodWhenNoAnnotatedBeans() { + // There are no beans with @TestAnnotation but there is an UnrelatedExampleBean + this.contextRunner + .withUserConfiguration(UnrelatedExampleBeanConfiguration.class, OnAnnotationMethodConfiguration.class) + .run((context) -> assertThat(context).hasBean("conditional")); + } + @Test void testOnMissingBeanConditionOutputShouldNotContainConditionalOnBeanClassInMessage() { this.contextRunner.withUserConfiguration(OnBeanNameConfiguration.class).run((context) -> { @@ -594,6 +602,17 @@ class ConditionalOnMissingBeanTests { } + @Configuration(proxyBeanMethods = false) + static class OnAnnotationMethodConfiguration { + + @Bean + @ConditionalOnMissingBean(annotation = TestAnnotation.class) + UnrelatedExampleBean conditional() { + return new UnrelatedExampleBean("conditional"); + } + + } + @Configuration(proxyBeanMethods = false) @ConditionalOnMissingBean(annotation = TestAnnotation.class) static class OnAnnotationWithFactoryBeanConfiguration { @@ -668,6 +687,16 @@ class ConditionalOnMissingBeanTests { } + @Configuration(proxyBeanMethods = false) + static class UnrelatedExampleBeanConfiguration { + + @Bean + UnrelatedExampleBean unrelatedExampleBean() { + return new UnrelatedExampleBean("test"); + } + + } + @Configuration(proxyBeanMethods = false) static class ImpliedOnBeanMethod { @@ -851,6 +880,21 @@ class ConditionalOnMissingBeanTests { } + static class UnrelatedExampleBean { + + private final String value; + + UnrelatedExampleBean(String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + + } + @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented