Closed
Description
Description
Previous to 3.4.0 (tested in 3.3.5), scoped beans using ScopedProxyMode.INTERFACES
or ScopedProxyMode.TARGET_CLASS
were being matched by any OnBeanCondition
that checked for annotations. (e.g. @ConditionOnMissingBean(annotation = SomeAnnotation.class)
). With 3.4.0 adding a check for autowire candidates and default candidates, this results in these beans no longer being matched.
Example
In this example testConditionalOnMissingBean()
passes in both 3.4.0
and 3.3.5
, but testConditionalOnMissingBean_Scoped()
fails in 3.4.0
and passes in 3.3.5
.
Note: In 3.3.5
the condition @ConditionalOnMissingBean(value = Void.class, annotation = AnnotationConditionQualifier.class)
was used to effectively disable type based matching.
Source
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@Qualifier
public @interface AnnotationConditionQualifier {
}
@AutoConfiguration
public class AnnotationConditionAutoConfiguration {
@Bean
@AnnotationConditionQualifier
@ConditionalOnMissingBean(annotation = AnnotationConditionQualifier.class)
public Supplier<String> supplier() {
return () -> "auto-configuration-string";
}
}
Test
class AnnotationConditionAutoConfigurationTest {
WebApplicationContextRunner runner;
@BeforeEach
void setUp() {
runner = new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(AnnotationConditionAutoConfiguration.class));
}
@Test
void testConditionalOnMissingBean_Scoped() {
runner.withUserConfiguration(ScopedConfig.class)
.run(context -> {
assertThat(context)
.getBeanNames(Supplier.class)
.containsExactlyInAnyOrder(
"customSupplier",
ScopedProxyUtils.getTargetBeanName("customSupplier")
);
});
}
@Test
void testConditionalOnMissingBean() {
runner.withUserConfiguration(Config.class)
.run(context -> {
assertThat(context)
.getBeanNames(Supplier.class)
.containsExactlyInAnyOrder(
"customSupplier"
);
});
}
@Configuration
@Import(CustomSupplier.class)
static class Config {
}
@Configuration
@Import(ScopedCustomSupplier.class)
static class ScopedConfig {
}
@Component("customSupplier")
@AnnotationConditionQualifier
static class CustomSupplier implements Supplier<String> {
@Override
public String get() {
return "custom-string";
}
}
@Component("customSupplier")
@AnnotationConditionQualifier
@Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES)
static class ScopedCustomSupplier implements Supplier<String> {
@Override
public String get() {
return "scoped-custom-string";
}
}
}